例如,给定
A = [1,51,3,1,100,199,3], maxSum = 51 + 1 + 199 = 251.
显然,max(oddIndexSum,evenIndexSum)
并不能起作用。
我面临的主要问题是我无法想出一个元素的选择标准。鉴别标准是微不足道的,只要有选择标准就能确定。
标准的最大子序列算法似乎不适用于这里。我尝试了动态规划方法,但也无法得出结果。我唯一能想到的方法是使用遗传算法。
你会如何解决这个问题呢?
例如,给定
A = [1,51,3,1,100,199,3], maxSum = 51 + 1 + 199 = 251.
显然,max(oddIndexSum,evenIndexSum)
并不能起作用。
我面临的主要问题是我无法想出一个元素的选择标准。鉴别标准是微不足道的,只要有选择标准就能确定。
标准的最大子序列算法似乎不适用于这里。我尝试了动态规划方法,但也无法得出结果。我唯一能想到的方法是使用遗传算法。
你会如何解决这个问题呢?
如果您保持两个状态,可以逐步构建最大子序列:
def maxsubseq(seq):
# maximal sequence including the previous item
incl = []
# maximal sequence not including the previous item
excl = []
for i in seq:
# current max excluding i
if sum(incl) > sum(excl):
excl_new = incl
else:
excl_new = excl
# current max including i
incl = excl + [i]
excl = excl_new
if sum(incl) > sum(excl):
return incl
else:
return excl
print maxsubseq([1,4,6,3,5,7,32,2,34,34,5])
如果您想在列表中包含负元素,就需要添加一些条件判断。
def maxsubseq2(iterable):
incl = [] # maximal sequence including the previous item
excl = [] # maximal sequence not including the previous item
for x in iterable:
# current max excluding x
excl_new = incl if sum(incl) > sum(excl) else excl
# current max including x
incl = excl + [x]
excl = excl_new
return incl if sum(incl) > sum(excl) else excl
sum()
def maxsubseq3(iterable):
incl = [] # maximal sequence including the previous item
excl = [] # maximal sequence not including the previous item
incl_sum, excl_sum = 0, 0
for x in iterable:
# current max excluding x
if incl_sum > excl_sum:
# swap incl, excl
incl, excl = excl, incl
incl_sum, excl_sum = excl_sum, incl_sum
else:
# copy excl to incl
incl_sum = excl_sum #NOTE: assume `x` is immutable
incl = excl[:] #NOTE: O(N) operation
assert incl is not excl
# current max including x
incl.append(x)
incl_sum += x
return incl if incl_sum > excl_sum else excl
好的,让我们对其进行优化...
def maxsubseq4(iterable):
incl = [] # maximal sequence including the previous item
excl = [] # maximal sequence not including the previous item
prefix = [] # common prefix of both sequences
incl_sum, excl_sum = 0, 0
for x in iterable:
if incl_sum >= excl_sum:
# excl <-> incl
excl, incl = incl, excl
excl_sum, incl_sum = incl_sum, excl_sum
else:
# excl is the best start for both variants
prefix.extend(excl) # O(n) in total over all iterations
excl = []
incl = []
incl_sum = excl_sum
incl.append(x)
incl_sum += x
best = incl if incl_sum > excl_sum else excl
return prefix + best # O(n) once
seq
上循环了 O(N) 次(除了 + [x]),这是一个O(N)操作 -> O(N)*O(N) -> O(N**2)。 - jfsmaxsubseq4()
看起来像是 O(N)。 - jfsprefix.extend(incl if incl_sum > excl_sum else excl)
呢?它所需的时间和内存至少比(prefix + best)
变体少一倍。 - jfs克里斯的答案在列表[9,10,9]上失败,产生了10而不是9+9=18。
乔说得不完全正确。旅行推销员需要访问每个城市,而这里没有类似的情况。
一种可能的解决方案是递归解决方案:
function Max_route(A)
if A's length = 1
A[0]
else
maximum of
A[0]+Max_route(A[2...])
Max_route[1...]
f [] :- [],0
f [x] :- [x],x
f [a,b] :- if a > b then [a],a else [b],b
f [a,b,t] :-
ft = f t
fbt = f [b|t]
if a + ft.sum > fbt.sum
[a|ft.path],a+ft.sum
else
fbt
dim max_sum_for_initial[n],next_to_get_max_of_initial[n],use_last_of_initial[n]
max_sum_for_initial[0] = 0
next_to_get_max_of_initial[0] = -1
use_last_of_initial[0] = false
max_sum_for_initial[1] = a[0]
next_to_get_max_of_initial[1] = -1
use_last_of_initial[1] = true
if a[0] > a[1]
max_sum_for_initial[2] = a[0]
next_to_get_max_of_initial[2] = 0
use_last_of_initial[2] = false
else
max_sum_for_initial[2] = a[1]
next_to_get_max_of_initial[1] = -1
use_last_of_initial[2] = true
for i from 3 to n
if a[i]+max_sum_for_initial[i-2] > max_sum_for_initial[i-1]
max_sum_for_initial[i] = a[i]+max_sum_for_initial[i-2]
next_to_get_max_of_initial[i] = i-2
use_last_of_initial[i] = true
else
max_sum_for_initial[i] = max+sum_for_initial[i-1]
next_to_get_max_of_initial[i] = i-1
use_last_of_initial[i] = false
for i = n; i >= 0; i = next_to_get_max_of_initial[i]
if use_last_of_initial[i] then print a[i]
find_max(int t, int n)
{
if(t>=n)
return 0;
int sum =0, max_sum =0;
for(int i=t; i<n; ++i)
{
sum = sum + A[i];
for(int j=i+2; j<n; ++j)
sum = sum + find_max(A[j], n);
if(sum > max_sum)
max_sum = sum;
}
return max_sum;
}
以上是一种递归解决方案,尚未编译。很容易看到重复的部分并将其转换为DP。很快会发布这个解决方案。
这里是使用动态规划完成的答案,使用了与MarkusQ相同的基本概念。我只计算总和,而不是实际序列,可以通过对此代码示例进行简单修改来生成序列。我很惊讶还没有人提到这一点,因为动态规划似乎比递归+记忆化更好!
int maxSeqSum(int *arr, int size) {
int i, a, b, c;
b = arr[0];
a = (arr[1] > arr[0]) ? arr[1]: arr[0];
for(i=2;i<size;i++) {
c = (a > (b + arr[i]))? a : (b + arr[i]);
b = a;
a = c;
}
return a;
}
一个奇怪的Prolog式伪代码中的递归答案:
maxSum([]) = 0
maxSum([x]) = x
maxSum(A) = max(A[0] + maxSum(A[2..n]),
A[1] + maxSum(A[3..n]))
在处理超出范围的索引时要适当处理。
编辑:这可以简化为MarcusQ更好的答案:
maxSum([]) = 0
maxSum(A) = max(A[0] + maxSum(A[2..n]), maxSum(A[1..n]))
编辑: 这里有一个版本,它返回实际的子序列而不仅仅是它们的总和。它挑战了我自己编写的伪Prolog-C Chimera的极限,所以我现在就停止。
maxSub([]) = []
maxSub(A) = sub1 = [A[0]] + maxSub(A[2..n])
sub2 = maxSub(A[1..n])
return sum(sub1) > sum(sub2) ? sub1 : sub2
[]
在伪Prolog-C中不表示链表,则如果涉及创建新子序列,则 [A[0]] + maxSub(A[2..n])
是O(N)操作(否则算法将无法工作)。 - jfs@MarkusQ的答案作为Python的一行代码(根据@recursive在评论中的建议进行修改):
f = lambda L: L and max([L[0]] + f(L[2:]), f(L[1:]), key=sum)
例子:
>>> f([1,51,3,1,100,199,3])
[51, 1, 199]
这种方法效率低下,但可以用于测试更快的解决方案。
(defun maxsubseq (L)
"Based on MarkusQ's and sth's answers."
(if (not L) L
(let ((incl (cons (car L) (maxsubseq (cddr L))))
(excl (maxsubseq (cdr L))))
(if (> (sum incl) (sum excl)) incl excl))))
(defun sum (L) (apply '+ L))
它基于@sth's answer:
(defun maxsubseq-iter-impl (L excl incl) (let ((next (if (> (car excl) (car incl)) excl incl)) (x (car L))) (if (not L) (cdr next) (maxsubseq-iter-impl (cdr L) next (cons (+ x (car excl)) (cons x (cdr excl)))))))
(defun maxsubseq-iter (L) (reverse (maxsubseq-iter-impl L '(0) '(0))))
(require 'cl) (loop for f in '(maxsubseq maxsubseq-iter) collect (loop for L in '((1 51 3 1 100 199 3) (9 10 9)) collect (f L)))
输出:
(((51 1 199) (9 9)) ((51 1 199) (9 9)))
maxSum(A,n): for all n
if n=0, maxSum = 0 else
if n=1, maxSum=A[1] else
maxSum = max(A[n] + maxSum(A,n-2), maxSum(A,n-1))
我们可以使用一个辅助数组B[0..n-1],其中B[i]是元素A[0..i]和C[0..n-1]的最大和,其中C[i]是布尔值,指示A[i]是否在最大和子序列中:
B[0]=max(A[0],0); C[0]=(A[0]>0)
B[1]=max(B[0],A[1]); C[1]=(A[1]>B[0])
for i in [2..n-1]
if A[i]+B[i-2] > B[i-1]
C[i]=True
B[i]=A[i]+B[i-2]
else
C[i]=False
B[i]=B[i-1]
mssq=[]
i=n-1
while i>=0
if C[i]
push(A[i],mssq)
i=i-2
else
i=i-1
return mssq
这显然可以在O(n)的时间和空间内工作。实际上,这与MarcusQ的解决方案相同,只是反转并进行了优化。
编辑:这实际上是另一个帖子的重复,但在发布后我没有意识到。
假设您不需要跟踪哪些项目对最终总和有贡献,您可以在常量空间和线性时间内完成此操作。
伪代码:
sum_excluded_last_item= 0
sum_included_last_item= 0
for each item in list
if (item>0)
last_sum_excluded_last_item= sum_excluded_last_item
sum_excluded_last_item= max(sum_included_last_item, sum_excluded_last_item + item)
sum_included_last_item= last_sum_excluded_last_item + item
else
sum_excluded_last_item= max(sum_excluded_last_item, sum_included_last_item)
sum_included_last_item= sum_excluded_last_item
max_sum= max(sum_excluded_last_item, sum_included_last_item)
A = [1, 51, 3, 2, 41, 23, 20]
,你可以有51 + 2 + 23 = 76
,或者你可以有51 + 41 + 20 = 112
,显然更大,也避免相邻元素。这是你要找的吗?