A Classical Interview Question

本文介绍了一种寻找列表中最大连续子序列和的有效算法,并提供了两种实现方式:一种通过跟踪增量和来确定最大子序列,另一种则通过动态更新候选起始点来简化计算过程。

The description of the question:

Locate the consecutive sub-list in a list that has the highest sum of values.

For example:

Given a list: (-1, 4, -2, 3, 1, 2, -2), the sub-list to return should be (4, -2, 3, 1, 2) with sum of values being 8.

First thought of the question:

The solution is expected to be with time complexity O(n), in which 'n' is the length of the original list.

As it seems to me, an intuitive way of achieving that is looking through the incremental sum of the list.

Since the sum of values in sub-list is represented in the incremental sum by the difference between the value of start point (one before the beginning of the sublist) and end point, locating the sublist with highest sum is a matter of finding two points with highest forward difference.

So an algorithm to deal with the problem should on one hand store the lowest point so far (the trough) and the highest increase in value from the lowest so far by inspecting and keeping track of the difference between the current value and that lowest point. Hence the implementation may look like the following:

public static int GetSubList(IList<int> source, out int begin, out int end) { int count = source.Count; int recSum = int.MinValue; int value = 0; int currIncSum = 0; int iTrough = -1; int lowestTrough = 0; begin = 0; end = 0; for (int i = 0; i < count; i++) { value = source[i]; currIncSum += value; if (currIncSum - lowestTrough > recSum && iTrough < i) { begin = iTrough + 1; end = i + 1; recSum = currIncSum - lowestTrough; } if (currIncSum < lowestTrough) { lowestTrough = currIncSum; iTrough = i; } } return recSum; }

In the source code, currIncSum keeps track of the current incremental sum value with begin and end marking the beginning and end of the sub-sequence, lowestTrough is the lowest value so far with iTrough being the position of the point.

The logic in the first conditional branch updates the highest increase, corresponding to the sublist with highest sum so far. The second conditional branch updates the lowest point and its value.

A subtle aspect of the task the algorithm is to achieve is how to deal with the case in which all values of the list are negative. Depending on the demand, the algorithm can return zero-lengthed list or the entry with highest value in the list as the sub-list. The above code implements the latter, with its recSum, the highest jump so far initialized to the minimal integer value.

Another way of handling the problem is simpler, and most likely more efficient but not as straightforward at a first glance. The code is as follows,


public static int GetSubList2(IList<int> a, out int begin, out int end) { int n = a.Count; int sum = a[0]; int b = 0; int ttBegin = 0; begin = 0; end = 1; for (int i = 0; i < n; i++) { if (b < 0) { b = a[i]; ttBegin = i; } else { b += a[i]; } if (sum < b) { begin = ttBegin; end = i + 1; sum = b; } } return sum; }

The idea is borrowed from (and a similar piece of code in C is provided by) July's blog post at:

http://blog.youkuaiyun.com/v_JULY_v/archive/2011/05/25/6444021.aspx

The key of this implementation is it exploited the fact that the candidate beginning point of the sublist only needs to be changed after the sum of current sublist is lower than zero (corresponding to in the perspective of the former algorithm, a new minimum value is found). The addition operation for the sum in this algorithm is reset, suspended and turned to an inspection of incoming value after such point is reached until the value turns to positive again. The process of recording the highest jump is performed in a separate logic that follows which keeps track of the sum value provided by the preceding logic. So the logic that generates the jump theoretically needs only to ensure it does not miss such a maximum value.

From this simple but typical example, we can see algorithmic problems need special attention from developers for them to make constant improvement in simplicity, efficiency, etc. and some of the changes can't be easily seen and require certain in-depth understanding, experience, changes in ways of thinking and even talents.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值