Kadane算法中如何返回最大子数组?

发布于 2024-12-10 01:47:25 字数 388 浏览 0 评论 0原文

public class Kadane {
  double maxSubarray(double[] a) {
    double max_so_far = 0;
    double max_ending_here = 0;

    for(int i = 0; i < a.length; i++) {
      max_ending_here = Math.max(0, max_ending_here + a[i]);
      max_so_far = Math.max(max_so_far, max_ending_here);
    }
    return max_so_far;
  }
}

上面的代码返回最大子数组的和。

我该如何返回具有最大总和的子数组?

public class Kadane {
  double maxSubarray(double[] a) {
    double max_so_far = 0;
    double max_ending_here = 0;

    for(int i = 0; i < a.length; i++) {
      max_ending_here = Math.max(0, max_ending_here + a[i]);
      max_so_far = Math.max(max_so_far, max_ending_here);
    }
    return max_so_far;
  }
}

The above code returns the sum of the maximum sub-array.

How would I instead return the sub-array which has the maximum sum?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

最好是你 2024-12-17 01:47:25

像这样的事情:

public class Kadane {
  double[] maxSubarray(double[] a) {
    double max_so_far = a[0];
    double max_ending_here = a[0];
    int max_start_index = 0;
    int startIndex = 0;
    int max_end_index = -1;

    for(int i = 1; i < a.length; i++) {
      if(a[i] > max_ending_here +a[i]) {
        startIndex = i;
        max_ending_here = a[i];
      }
      else {
        max_ending_here += a[i];
      }

      if(max_ending_here > max_so_far) {
        max_so_far = max_ending_here;
        max_start_index = startIndex;
        max_end_index = i;
      }
    }

    if(max_start_index <= max_end_index) {
      return Arrays.copyOfRange(a, max_start_index, max_end_index+1);
    }

    return null;
  }
}

OPDATE:还处理数组中所有负数的情况,并且总和的默认值为 0。

Something like this:

public class Kadane {
  double[] maxSubarray(double[] a) {
    double max_so_far = a[0];
    double max_ending_here = a[0];
    int max_start_index = 0;
    int startIndex = 0;
    int max_end_index = -1;

    for(int i = 1; i < a.length; i++) {
      if(a[i] > max_ending_here +a[i]) {
        startIndex = i;
        max_ending_here = a[i];
      }
      else {
        max_ending_here += a[i];
      }

      if(max_ending_here > max_so_far) {
        max_so_far = max_ending_here;
        max_start_index = startIndex;
        max_end_index = i;
      }
    }

    if(max_start_index <= max_end_index) {
      return Arrays.copyOfRange(a, max_start_index, max_end_index+1);
    }

    return null;
  }
}

UPDATE by the OP: also handle the cases with all negative numbers in the array and default of the sum is 0.

可爱暴击 2024-12-17 01:47:25

上面的代码有一个错误。应该是:

max_ending_here = Math.max(a[i], max_ending_here + a[i]);

NOT:

max_ending_here = Math.max(0, max_ending_here + a[i]);

如果不是,则会失败,例如: 2 , 4, 22, 19, -48, -5 , 20, 40 并返回 55 而不是正确答案 60。

参见 Kadane 算法 http://en.wikipedia.org/wiki/Maximum_subarray_problem

The code above has an error. Should be:

max_ending_here = Math.max(a[i], max_ending_here + a[i]);

NOT:

max_ending_here = Math.max(0, max_ending_here + a[i]);

If not, would fail for a sequence such as: 2 , 4, 22, 19, -48, -5 , 20, 40 and return 55 instead of the correct answer of 60.

SEE Kadane algorithm at http://en.wikipedia.org/wiki/Maximum_subarray_problem

葵雨 2024-12-17 01:47:25

我将 max_so_far 维护在一个列表中:

for(int i = 0;i<N;i++){
    max_end_here = Math.max(seq[i], max_end_here + seq[i]);
    sum_list.add(max_end_here);
    // System.out.println(max_end_here);
    max_so_far = Math.max(max_so_far, max_end_here);
}

然后搜索列表中最大的总和,其索引作为子序列结束。
从索引开始向后查找,找到最后一个值为正的索引。后续的开始就是这个索引。

for(int i=sum_list.size()-1; i>=0; i--){
    if(sum_list.get(i) == max_so_far){
        end = i;
        while(sum_list.get(i) > 0 && i>=0){
            i--;
        }
        start = (i==-1)?0:i+1;
        break;
    }
}

I maintain the max_so_far in a list:

for(int i = 0;i<N;i++){
    max_end_here = Math.max(seq[i], max_end_here + seq[i]);
    sum_list.add(max_end_here);
    // System.out.println(max_end_here);
    max_so_far = Math.max(max_so_far, max_end_here);
}

Then search the biggest sum in list, its index as sub sequnece end.
Start from index as end and search backwards, find the last index whose value is positive. Subsequence start is this index.

for(int i=sum_list.size()-1; i>=0; i--){
    if(sum_list.get(i) == max_so_far){
        end = i;
        while(sum_list.get(i) > 0 && i>=0){
            i--;
        }
        start = (i==-1)?0:i+1;
        break;
    }
}
拔了角的鹿 2024-12-17 01:47:25

与算法密切相关的更简单的方法。

int main()
{
   int a[]={-2, 1, -3, 4, -1, 2, 1, -5, 4};
   int size=sizeof(a)/sizeof(a[0]);
   int startIndex=0,endIndex=0,i,j;
   int max_so_far=0,max_sum=-999;
   for(i=0;i<size;i++)
   {
   max_so_far=max_so_far+a[i];//kadane's algorithm step 1
   if(max_so_far>max_sum) //computing max
   {
      max_sum=max_so_far;
      endIndex=i;
   }

   if(max_so_far<0)
   {
   max_so_far=0;
   startIndex=i+1;
   }
}
   cout<<max_so_far<<" "<<startIndex<<" "<<endIndex;
   getchar();
   return 0;
}

一旦有了开始和结束索引。

for(i=startIndex;i<=endIndex;i++)
{
cout<<a[i];
}

A more easier approach closely linked to the algorithm.

int main()
{
   int a[]={-2, 1, -3, 4, -1, 2, 1, -5, 4};
   int size=sizeof(a)/sizeof(a[0]);
   int startIndex=0,endIndex=0,i,j;
   int max_so_far=0,max_sum=-999;
   for(i=0;i<size;i++)
   {
   max_so_far=max_so_far+a[i];//kadane's algorithm step 1
   if(max_so_far>max_sum) //computing max
   {
      max_sum=max_so_far;
      endIndex=i;
   }

   if(max_so_far<0)
   {
   max_so_far=0;
   startIndex=i+1;
   }
}
   cout<<max_so_far<<" "<<startIndex<<" "<<endIndex;
   getchar();
   return 0;
}

Once you have start and End index.

for(i=startIndex;i<=endIndex;i++)
{
cout<<a[i];
}
岁月静好 2024-12-17 01:47:25

我们可以使用以下代码来跟踪最大子数组:

import java.util.Arrays;

public class KadaneSolution4MaxSubArray{

    public static void main(String[]args){
        int [] array = new int[]{13,-3,-25,20 ,-3 ,-16,-23,18,20,-7,12,-5,-22,15,-4,7};

        int[] maxSubArray = maxSubArrayUsingKadaneSol(array);
        for(int e : maxSubArray){
                System.out.print(e+"\t");
            }
        System.out.println();
    }

    public static int[] maxSubArrayUsingKadaneSol(int array[]){
        long maxSoFar =array[0];
        long maxEndingHere =array[0];
        int startIndex = 0;
        int endIndex =0;
        int j=1;
        for(; j< array.length ;j++){
            int val = array[j];
            if(val >= val+maxEndingHere){
                    maxEndingHere = val;
                    startIndex = j;
                }else {
                    maxEndingHere += val;
                    };
            if(maxSoFar < maxEndingHere){
                    maxSoFar = maxEndingHere;
                    endIndex = j;
                }
            }

            return Arrays.copyOfRange(array,startIndex,endIndex+1);
    }   
}

PS 假设给定数组是最大子数组问题的候选者,并且所有元素都不为负

we can keep track max subarray by using following code :

import java.util.Arrays;

public class KadaneSolution4MaxSubArray{

    public static void main(String[]args){
        int [] array = new int[]{13,-3,-25,20 ,-3 ,-16,-23,18,20,-7,12,-5,-22,15,-4,7};

        int[] maxSubArray = maxSubArrayUsingKadaneSol(array);
        for(int e : maxSubArray){
                System.out.print(e+"\t");
            }
        System.out.println();
    }

    public static int[] maxSubArrayUsingKadaneSol(int array[]){
        long maxSoFar =array[0];
        long maxEndingHere =array[0];
        int startIndex = 0;
        int endIndex =0;
        int j=1;
        for(; j< array.length ;j++){
            int val = array[j];
            if(val >= val+maxEndingHere){
                    maxEndingHere = val;
                    startIndex = j;
                }else {
                    maxEndingHere += val;
                    };
            if(maxSoFar < maxEndingHere){
                    maxSoFar = maxEndingHere;
                    endIndex = j;
                }
            }

            return Arrays.copyOfRange(array,startIndex,endIndex+1);
    }   
}

P.S. Assume that given array is candidate of Max sub array problem as well as not having all elements negative

哎呦我呸! 2024-12-17 01:47:25

每次启动新的子数组和时更新可能的左(起始)索引。 max_sum 更新后,更新最终的左和右(结尾)。还维护一个触发器,告知是否创建了新的子数组和。

int last = 0;
    int sum  = Integer.MIN_VALUE;
    boolean fOrReset = true;
    int _L = -1, L = -1, R = -1;

    for (int j = 0; j < arr.length; j++) {
        last += arr[j];
        if (fOrReset) {
            _L = j+1;
        }
        fOrReset = false;
        if (sum < last) {
            sum = last;
            L = _L;
            R = j+1;
        }
        if (last < 0) {
            last = 0;
            fOrReset = true;
        }
    }

Update the probable left(starting) index every time a new sub-array sum is initiated. Update the final left and right(ending) once the max_sum is updated. Also maintain a trigger that tells if a new sub-array sum is created.

int last = 0;
    int sum  = Integer.MIN_VALUE;
    boolean fOrReset = true;
    int _L = -1, L = -1, R = -1;

    for (int j = 0; j < arr.length; j++) {
        last += arr[j];
        if (fOrReset) {
            _L = j+1;
        }
        fOrReset = false;
        if (sum < last) {
            sum = last;
            L = _L;
            R = j+1;
        }
        if (last < 0) {
            last = 0;
            fOrReset = true;
        }
    }
焚却相思 2024-12-17 01:47:25
private static int[] applyKadaneAlgorithmGetSubarrayOptimized(int[] input) {
    int localMax = input[0];
    int globalMax = input[0];
    int start = 0;
    int end = 0;
    for (int i = 1; i < input.length; i++) {
        localMax = Math.max(localMax + input[i], input[i]);
        if(localMax == input[i]) { //this is similar as --> input[i] > (localMax + input[i])
            start = i;
        }
        if(localMax > globalMax) {
            end = i;
        }
        globalMax = Math.max(localMax, globalMax);
    }

    //Below condition only occur`enter code here`s when all members of the array are negative integers
    //Example: {-9, -10, -6, -7, -8, -1, -2, -4}
    if(start > end) {
        start = end;
    }

    return Arrays.copyOfRange(input, start, end + 1);
}
private static int[] applyKadaneAlgorithmGetSubarrayOptimized(int[] input) {
    int localMax = input[0];
    int globalMax = input[0];
    int start = 0;
    int end = 0;
    for (int i = 1; i < input.length; i++) {
        localMax = Math.max(localMax + input[i], input[i]);
        if(localMax == input[i]) { //this is similar as --> input[i] > (localMax + input[i])
            start = i;
        }
        if(localMax > globalMax) {
            end = i;
        }
        globalMax = Math.max(localMax, globalMax);
    }

    //Below condition only occur`enter code here`s when all members of the array are negative integers
    //Example: {-9, -10, -6, -7, -8, -1, -2, -4}
    if(start > end) {
        start = end;
    }

    return Arrays.copyOfRange(input, start, end + 1);
}
远昼 2024-12-17 01:47:25

我知道这是一个旧线程,但为了清楚起见,我想分享我的解决方案版本。

  • sumMax 是存储 maxSubArray sum 的变量
  • subSum 是临时变量,用于比较 sum 是否增加。
  • 我们知道,只有当 subSum 重新开始时,我们才应该移动下限

public static int maxSubArray(int[] a, out int[] subArr){
        int sumMax = int.MinValue;
        int subSum = 0;
        int iLow = 0, iHigh = 0;
        for(int i=0; i<a.Length; i++){
            subSum+=a[i];
            if(subSum>sumMax){
                sumMax = subSum;
                //move high (upper bound) since sumMax increased 
                iHigh = i;
                
                //if the subSum is new, then move lower bound
                if(subSum == a[i]){
                    iLow = i;
                }
            }
            subSum = Math.Max(subSum, 0);
        }
        
        //build the array - returned as an out parameter
        int index = 0;
        subArr = new int[iHigh-iLow+1];
        while(iLow <= iHigh){
            subArr[index++] = a[iLow++];
        } 
        
        return sumMax;
    } 

I know this is an old thread, but wanted to share my version of the solution for clarity.

  • sumMax is the variable storing the maxSubArray sum
  • subSum is the temporary variable used to compare if sum increased or not.
  • We know that we should move the lower bound only if subSum has started over

public static int maxSubArray(int[] a, out int[] subArr){
        int sumMax = int.MinValue;
        int subSum = 0;
        int iLow = 0, iHigh = 0;
        for(int i=0; i<a.Length; i++){
            subSum+=a[i];
            if(subSum>sumMax){
                sumMax = subSum;
                //move high (upper bound) since sumMax increased 
                iHigh = i;
                
                //if the subSum is new, then move lower bound
                if(subSum == a[i]){
                    iLow = i;
                }
            }
            subSum = Math.Max(subSum, 0);
        }
        
        //build the array - returned as an out parameter
        int index = 0;
        subArr = new int[iHigh-iLow+1];
        while(iLow <= iHigh){
            subArr[index++] = a[iLow++];
        } 
        
        return sumMax;
    } 
埋情葬爱 2024-12-17 01:47:25

C++ 中的另一个实现,Kadane(实际上只是动态编程方法)和带有索引计算和一些注释的扩展 Kadane:

    int maxSubArray(vector<int>& nums) 
    {        
        int n = nums.size();
        
        if(n == 0) return INT_MIN;
        
        // max sum that ends at index I
        int sumMaxI = nums[0];
        
        // total max sum
        int sumMax = nums[0];
        for(int i = 1; i < n; i++)
        {  
            int curr = nums[i];
            
            // calc current max sum that ends at I
            int currSumMaxI = sumMaxI + curr;
            
            // calc new max sum that ends at I
            sumMaxI = max(currSumMaxI, curr);
            
            // calc new total max sum
            sumMax = max(sumMax, sumMaxI);
        }
        
        return sumMax;
    }    
    
    
    int maxSubArray_findBeginEnd(vector<int>& nums) 
    {        
        int n = nums.size();
        
        if(n == 0) return INT_MIN;
        
        // max sum that ends at index I
        int sumMaxI = nums[0];
        // start index for max sum (end index is I)
        int sumMaxIStart = 0;
                
        // total max sum
        int sumMax = nums[0];
        // start and end index for total max sum
        int sumMaxStart = 0;
        int sumMaxEnd = 0;
        for(int i = 1; i < nums.size(); i++)
        {  
            int curr = nums[i];
            
            // calc current max sum that ends at I
            int currSumMaxI = sumMaxI + curr;
            
            // calc new min sum that ends at I and its starting index
            // this part is equal to: sumMaxI = max(currSumMaxI, curr);
            // but additionaly enables to save new start index as well
            if(curr > currSumMaxI)
            {
                sumMaxI = curr;
                sumMaxIStart = i;
            }
            else
                sumMaxI = currSumMaxI;
                 
            // calculate total max sum
            // this part is equal to: sumMax = max(sumMax, sumMaxI);
            if(sumMaxI > sumMax)
            {
                sumMax = sumMaxI;
                sumMaxStart = sumMaxIStart;
                sumMaxEnd = i;
            }
            // this part is to additionaly capture longest subarray among all that have max sum
            // also, of all subarrays with max sum and max len, one with smallest index
            // will be captured
            else if(sumMaxI == sumMax) 
            {
                if(i - sumMaxIStart > sumMaxEnd - sumMaxStart)
                {
                    sumMaxStart = sumMaxIStart;
                    sumMaxEnd = i;
                }
            }
        }
        
        // check validity of start and end indices
        int checkSum = 0;
        for(int i = sumMaxStart; i <= sumMaxEnd; i++)
            checkSum += nums[i];
        assert(checkSum == sumMax); 
        
        // output indices
        cout << "Max subarray indices: [" << sumMaxStart << "," << sumMaxEnd << "]" << endl;
        
        return sumMax;
    }    

Another implementation in C++, both Kadane (which is actually just dynamic programming approach) and extended Kadane with indices calculation and some comments:

    int maxSubArray(vector<int>& nums) 
    {        
        int n = nums.size();
        
        if(n == 0) return INT_MIN;
        
        // max sum that ends at index I
        int sumMaxI = nums[0];
        
        // total max sum
        int sumMax = nums[0];
        for(int i = 1; i < n; i++)
        {  
            int curr = nums[i];
            
            // calc current max sum that ends at I
            int currSumMaxI = sumMaxI + curr;
            
            // calc new max sum that ends at I
            sumMaxI = max(currSumMaxI, curr);
            
            // calc new total max sum
            sumMax = max(sumMax, sumMaxI);
        }
        
        return sumMax;
    }    
    
    
    int maxSubArray_findBeginEnd(vector<int>& nums) 
    {        
        int n = nums.size();
        
        if(n == 0) return INT_MIN;
        
        // max sum that ends at index I
        int sumMaxI = nums[0];
        // start index for max sum (end index is I)
        int sumMaxIStart = 0;
                
        // total max sum
        int sumMax = nums[0];
        // start and end index for total max sum
        int sumMaxStart = 0;
        int sumMaxEnd = 0;
        for(int i = 1; i < nums.size(); i++)
        {  
            int curr = nums[i];
            
            // calc current max sum that ends at I
            int currSumMaxI = sumMaxI + curr;
            
            // calc new min sum that ends at I and its starting index
            // this part is equal to: sumMaxI = max(currSumMaxI, curr);
            // but additionaly enables to save new start index as well
            if(curr > currSumMaxI)
            {
                sumMaxI = curr;
                sumMaxIStart = i;
            }
            else
                sumMaxI = currSumMaxI;
                 
            // calculate total max sum
            // this part is equal to: sumMax = max(sumMax, sumMaxI);
            if(sumMaxI > sumMax)
            {
                sumMax = sumMaxI;
                sumMaxStart = sumMaxIStart;
                sumMaxEnd = i;
            }
            // this part is to additionaly capture longest subarray among all that have max sum
            // also, of all subarrays with max sum and max len, one with smallest index
            // will be captured
            else if(sumMaxI == sumMax) 
            {
                if(i - sumMaxIStart > sumMaxEnd - sumMaxStart)
                {
                    sumMaxStart = sumMaxIStart;
                    sumMaxEnd = i;
                }
            }
        }
        
        // check validity of start and end indices
        int checkSum = 0;
        for(int i = sumMaxStart; i <= sumMaxEnd; i++)
            checkSum += nums[i];
        assert(checkSum == sumMax); 
        
        // output indices
        cout << "Max subarray indices: [" << sumMaxStart << "," << sumMaxEnd << "]" << endl;
        
        return sumMax;
    }    
软糖 2024-12-17 01:47:25

当我们确实得到 max_so_far 时,更新 max_start_index 和 max_end_index 。 start_index 不断变化,因此,跟踪它并在找到 max 时将其存储到 max_start_index 中。

class Solution {
    public int maxSubArray(int[] nums) {
        int max_so_far = nums[0];
        int max_end_here = nums[0];
        int max_start_index = 0;
        int start_index = 0;
        int max_end_index = 0;
        for (int i=1; i<nums.length; i++) {
            max_end_here = max_end_here + nums[i];
            if (max_end_here<0) {
                start_index = i+1;
                max_end_here=0;
            }
            if (max_so_far < max_end_here) {
                max_start_index = start_index;
                max_end_index = i;
                max_so_far = max_end_here;
            }
        }
        System.out.println("i="+max_start_index+";j="+max_end_index);
        return max_so_far;
        
    }
}

Update the max_start_index and max_end_index when we indeed got the max_so_far. start_index keeps changing so, keep track of it and store it into max_start_index when you found max.

class Solution {
    public int maxSubArray(int[] nums) {
        int max_so_far = nums[0];
        int max_end_here = nums[0];
        int max_start_index = 0;
        int start_index = 0;
        int max_end_index = 0;
        for (int i=1; i<nums.length; i++) {
            max_end_here = max_end_here + nums[i];
            if (max_end_here<0) {
                start_index = i+1;
                max_end_here=0;
            }
            if (max_so_far < max_end_here) {
                max_start_index = start_index;
                max_end_index = i;
                max_so_far = max_end_here;
            }
        }
        System.out.println("i="+max_start_index+";j="+max_end_index);
        return max_so_far;
        
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文