Algorithm 整数数组的最大子数组 在一次采访中,我的一个朋友被要求找到一个最大的数组的子数组,这是我的问题的解决方案,我如何改进解决方案使它更优化,我应该考虑以递归的方式做吗?p> def get_max_sum_subset(x): max_subset_sum = 0 max_subset_i = 0 max_subset_j = 0 for i in range(0,len(x)+1): for j in range(i+1,len(x)+1): current_sum = sum(x[i:j]) if current_sum > max_subset_sum: max_subset_sum = current_sum max_subset_i = i max_subset_j = j return max_subset_sum,max_subset_i,max_subset_j
通过考虑最大和子数组必须满足的条件,可以得出一种更好的解决方法:两端未包含的第一项(如果有)必须为负,两端包含的最后一项必须为非负。除了在原始数据中发生这些变化之外,您不需要考虑子阵列的任何其他端点。 下面是一个来自Algorithm 整数数组的最大子数组 在一次采访中,我的一个朋友被要求找到一个最大的数组的子数组,这是我的问题的解决方案,我如何改进解决方案使它更优化,我应该考虑以递归的方式做吗?p> def get_max_sum_subset(x): max_subset_sum = 0 max_subset_i = 0 max_subset_j = 0 for i in range(0,len(x)+1): for j in range(i+1,len(x)+1): current_sum = sum(x[i:j]) if current_sum > max_subset_sum: max_subset_sum = current_sum max_subset_i = i max_subset_j = j return max_subset_sum,max_subset_i,max_subset_j,algorithm,Algorithm,通过考虑最大和子数组必须满足的条件,可以得出一种更好的解决方法:两端未包含的第一项(如果有)必须为负,两端包含的最后一项必须为非负。除了在原始数据中发生这些变化之外,您不需要考虑子阵列的任何其他端点。 下面是一个来自 除非我遗漏了一些重要的东西,如果它们是正整数,子集将包括整个数组,如果它们是整数,它将只包括正整数。还有其他限制吗?您的解决方案是O(n^2)。最优解是线性的。它的工作原理是从左到右扫描阵列,并记录最佳和和和当前和: def get_max_sum_subset(x): b
除非我遗漏了一些重要的东西,如果它们是正整数,子集将包括整个数组,如果它们是整数,它将只包括正整数。还有其他限制吗?您的解决方案是O(n^2)。最优解是线性的。它的工作原理是从左到右扫描阵列,并记录最佳和和和当前和:
def get_max_sum_subset(x):
bestSoFar = 0
bestNow = 0
bestStartIndexSoFar = -1
bestStopIndexSoFar = -1
bestStartIndexNow = -1
for i in xrange(len(x)):
value = bestNow + x[i]
if value > 0:
if bestNow == 0:
bestStartIndexNow = i
bestNow = value
else:
bestNow = 0
if bestNow > bestSoFar:
bestSoFar = bestNow
bestStopIndexSoFar = i
bestStartIndexSoFar = bestStartIndexNow
return bestSoFar, bestStartIndexSoFar, bestStopIndexSoFar
在(强烈推荐)中也讨论了此问题。在那里你还可以找到一个递归的解决方案,它不是最优的(O(n logn)),但比O(n^2)要好。让
n
-元素计数,a(i)
-你的数组f(i)
-在i
位置结束的子数组的最大和(最小长度为1)。然后:
max(0,f(1),f(2),…,f(n-1))
-答案这是一个众所周知的问题,显示了重叠的最优子结构,建议采用动态规划(DP)解决方案。虽然DP解决方案通常相当棘手(我认为至少如此!),但这是一个很好的例子,可以介绍整个概念
首先要注意的是,结束于位置j的最大子阵列(必须是给定阵列a的连续部分)要么由结束于位置j-1加上a[j]的最大子阵列组成,要么为空(仅当a[j]<0时才会发生这种情况)。换句话说,我们要问的是,元素A[j]是否对当前的最大和起到了积极的作用,该和在位置j-1处结束。如果是,则将其包含在迄今为止的最大子阵列中;如果没有,就不要。因此,通过解决重叠的较小子问题,我们可以建立最佳解决方案
然后,可以通过以下关系递归地给出终止于位置j的最大子阵列的和:
sum[0] = max(0, A[0])
sum[j] = max(0, sum[j-1] + A[j])
我们可以通过从左到右扫描a,以自下而上的方式建立这些答案。当我们考虑[j]时,我们更新和[j]。通过这个过程,我们还可以跟踪整体最大值和最大子阵列的位置。下面是我用Ruby编写的一个快速解决方案:
def max_subarray(a)
sum = [0]
max, head, tail = sum[0], -1, -1
cur_head = 0
(0...a.size).each do |j|
# base case included below since sum[-1] = sum[0]
sum[j] = [0, sum[j-1] + a[j]].max
cur_head = j if sum[j-1] == 0
if sum[j] > max
max, head, tail = sum[j], cur_head, j
end
end
return max, head, tail
end
如果你想自己测试一下,看看我的
这显然是一个线性O(N)算法,因为只需要通过列表一次。希望这有帮助 麻省理工学院有一段短片,帮助您理解这个动态编程问题。 单击“问题”部分下的第一个链接,您将看到它。Java解决方案: 不适用于所有负片的数组
public static int[] maxsubarray(int[] array) {
//empty array check
if (array.length == 0){
return new int[]{};
}
int max = 0;
int maxsofar = 0;
//indices
int maxsofarstart = 0;
int maxsofarend = 0;
int maxstartindex = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] > 0) {
if (max == 0) {
maxstartindex = i;
}
max = max + array[i];
if (max > maxsofar) {
maxsofar = max;
maxsofarstart = maxstartindex;
maxsofarend = i;
}
} else {
max = 0;
}
}
return Arrays.copyOfRange(array, maxsofarstart, maxsofarend + 1);
}
公共静态int[]maxsubarray(int[]array){
//空数组检查
如果(array.length==0){
返回新的int[]{};
}
int max=0;
int maxsofar=0;
//指数
int maxsofarstart=0;
int maxsofarend=0;
int maxstartindex=0;
for(int i=0;i0){
如果(最大==0){
maxstartindex=i;
}
max=max+array[i];
如果(最大值>最大值){
最大值=最大值;
maxsofarstart=maxstartindex;
maxsofarend=i;
}
}否则{
max=0;
}
}
返回数组.copyOfRange(数组,maxsofarstart,maxsofarend+1);
}
这是一个解释得最清楚、测试得最有效的解决方案-
package me.rerun;
公共级卡丹{
公共静态void main(字符串[]args){
int[]intArr={3,-1,-1,-1,2,0,0,0};
//int[]intArr={-1,3,-5,4,6,-1,2,-7,13,-3};
//int[]intArr={-6,-2,-3,-4,-1,-5};
FindMax子阵列(intArr);
}
公共静态无效findMaxSubArray(int[]输入阵列){
int maxStartIndex=0;
int maxEndIndex=0;
int maxSum=Integer.MIN_值;
int-cumulativeSum=0;
int maxStartIndexUntilNow=0;
对于(int currentIndex=0;currentIndex最大和){
maxSum=累积量;
maxStartIndex=maxStartIndexUntilNow;
maxEndIndex=currentIndex;
}
else if(cumulativeSum这是正确的Java代码,它将处理包括所有负数在内的场景
public static long[] leftToISumMaximize(int N, long[] D) {
long[] result = new long[N];
result[0] = D[0];
long currMax = D[0];
for (int i = 1; i < N; i++) {
currMax = Math.max(D[i], currMax + D[i]);
result[i] = Math.max(result[i - 1], currMax);
}
return result;
}
public static long[]leftToSummaximize(int N,long[]D){
long[]结果=新的long[N];
结果[0]=D[0];
长电流最大值=D[0];
对于(int i=1;i
我为一个更一般的问题创建了一个函数:
- 查找最大和子数组(表示其边界和和,而不仅仅是和)
- 如果两个子阵列的和相等,则选择较短的一个子阵列
- 如果两个等长的子阵列具有相等的和,则选择第一个出现的子阵列
函数基于Kadane的算法,在O(n)时间内运行。基本上,就是这样:
function MaxSumSubarray(a, n, start out, len out)
-- a - Array
-- n - Length of the array
-- start - On output starting position of largest subarray
-- len - On output length of largest subarray
-- Returns sum of the largest subarray
begin
start = 0
len = 1
int sum = a[0]
curStart = 0
curLen = 1
curSum = a[0]
for i = 2 to n
begin
if a[i] >= curSum + a[i] then
begin
curStart = i
curLen = 1
curSum = a[i]
end
else
begin
curLen = curLen + 1
curSum = curSum + a[i]
end
if (curSum > sum) OR
(curSum = sum AND curLen < len) OR
(curSum = sum AND curLen = len AND curStart < start) then
begin
start = curStart
len = curLen
sum = curSum
end
end
return sum
end
函数MaxSum子阵列(a、n、起始输出、len输出)
--a-数组
--n-数组的长度
--开始-最大子阵列的输出开始位置
--len-关于最大子阵列的输出长度
--返回最大子数组的和
开始
开始=0
莱恩=
package me.rerun;
public class Kadane {
public static void main(String[] args) {
int[] intArr={3, -1, -1, -1, -1, -1, 2, 0, 0, 0 };
//int[] intArr = {-1, 3, -5, 4, 6, -1, 2, -7, 13, -3};
//int[] intArr={-6,-2,-3,-4,-1,-5,-5};
findMaxSubArray(intArr);
}
public static void findMaxSubArray(int[] inputArray){
int maxStartIndex=0;
int maxEndIndex=0;
int maxSum = Integer.MIN_VALUE;
int cumulativeSum= 0;
int maxStartIndexUntilNow=0;
for (int currentIndex = 0; currentIndex < inputArray.length; currentIndex++) {
int eachArrayItem = inputArray[currentIndex];
cumulativeSum+=eachArrayItem;
if(cumulativeSum>maxSum){
maxSum = cumulativeSum;
maxStartIndex=maxStartIndexUntilNow;
maxEndIndex = currentIndex;
}
else if (cumulativeSum<0){
maxStartIndexUntilNow=currentIndex+1;
cumulativeSum=0;
}
}
System.out.println("Max sum : "+maxSum);
System.out.println("Max start index : "+maxStartIndex);
System.out.println("Max end index : "+maxEndIndex);
}
}
public static long[] leftToISumMaximize(int N, long[] D) {
long[] result = new long[N];
result[0] = D[0];
long currMax = D[0];
for (int i = 1; i < N; i++) {
currMax = Math.max(D[i], currMax + D[i]);
result[i] = Math.max(result[i - 1], currMax);
}
return result;
}
function MaxSumSubarray(a, n, start out, len out)
-- a - Array
-- n - Length of the array
-- start - On output starting position of largest subarray
-- len - On output length of largest subarray
-- Returns sum of the largest subarray
begin
start = 0
len = 1
int sum = a[0]
curStart = 0
curLen = 1
curSum = a[0]
for i = 2 to n
begin
if a[i] >= curSum + a[i] then
begin
curStart = i
curLen = 1
curSum = a[i]
end
else
begin
curLen = curLen + 1
curSum = curSum + a[i]
end
if (curSum > sum) OR
(curSum = sum AND curLen < len) OR
(curSum = sum AND curLen = len AND curStart < start) then
begin
start = curStart
len = curLen
sum = curSum
end
end
return sum
end
.....(I wrote it in Scala)
def findMaxSubArray(list: List[Int]): (Int, Int, Int) = {
var (bestNow,bestSoFar) = (0, 0)
var ( startIndexNow, startIndexSoFar, endIndex) = (-1, -1, -1)
for (i <- 0 until list.length) {
var value = bestNow + list(i)
if (value > bestNow) {
if (bestNow == 0)
startIndexNow = i
bestNow = value
} else
bestNow = 0
if (bestNow > bestSoFar) {
bestSoFar = bestNow
startIndexSoFar = startIndexNow
endIndex = i
}
}
return (bestSoFar, startIndexSoFar, endIndex)
}
def main(args: Array[String]) {
println(findMaxSubArray(List(3, -1, 5, 3, -6, -9, 6, 1)).toString)
println(findMaxSubArray(List(3, -1, 5, 3, -6, -9, 6, 3)).toString)
println(findMaxSubArray(List(20, -1, 5, 3, -6, -9, 6)).toString)
}
Output.....
(max =8, start=2, end=3)
(max=9, start=6, end=7)
(max=20, start=0, end= 0)