繁体   English   中英

最大和子数组

[英]Maximum Sum SubArray

我试图在具有最大总和的数组中找到连续的子数组。 所以,对于数组

{5, 15, -30, 10, -5, 40, 10}

连续使用这些数字的最大和可能是 55,或 (10 + (-5) + 40 + 10) = 55。下面的程序输出最大和 55,但是,我想弄清楚的问题是如何打印产生这个 55 的序列。换句话说,我如何打印出 10、-5、40 和 10?

public static void main(String[] args) {
    int[] arr = {5, 15, -30, 10, -5, 40, 10};

    System.out.println(maxSubsequenceSum(arr));         
}

public static int maxSubsequenceSum(int[] X) {
    int max = X[0];
    int sum = X[0];

    for (int i = 1; i < X.length; i++) {
        sum = Math.max(X[i], sum + X[i]);
        max = Math.max(max, sum);
    }
    return max;
}

我正在考虑创建一个 ArrayList 来存储 i 的每个索引处的sum值,因此 ArrayList 看起来像 (5, 20, -10, 10, 5, 45, 55)。 然后我打算将 ArrayList 从索引 0 清除到列表中的第一个负数,但是,这只能解决此特定示例的问题,但是如果我更改原始数字数组,则此解决方案将不起作用。

您可以用 if 语句替换 Math.Max 函数并更新最佳子数组的开始和结束索引。 帕斯卡版本:

    if X[i] > sum + X[i] then begin
        sum := X[i];
        start := i;
      end
      else
        sum := sum + X[i];
      if max < sum then begin
        max := sum;
        finish := i;
      end;

您可以跟踪循环中当前最佳子数组的开始和结束索引。 不要使用max()来计算summax ,只需执行以下操作:

int sum_start = 0, sum_end = 0, start = 0, end = 0;
// In the for loop
if (X[i] > sum + X[i]) {
    sum = X[i];
    sum_start = i;
    sum_end = i;
} else {
    ++sum_end;
}
if (sum > max) {
    start = sum_start;
    end = sum_end;
    max = sum;
}

有一个 o(n) 解决方案,一个循环遍历数组并在当前总数低于 0 时重置您的子序列。

{5, 15, -30, 10, -5, 40, 10}

  • 5 + 15 = 20
  • 20 - 30 = -10(重置子序列)
  • 10 -5 +40 +10 = 55
  • 结尾。 55 是最大子序列

编辑:获取子序列...每当您更改最大值时,请更新您的子序列

  • 当前左索引仅在您重置时更改
  • 当前正确的索引每次迭代都会改变
  • new max -> 保存当前左右索引...

可以通过在识别最大子数组的同时捕获开始和结束来完成,如下所示:

代码

package recursion;

import java.util.Arrays;

public class MaximumSubArray {

    private static SubArray maxSubArray(int[] values, int low, int high) {
        if (low == high) {
            // base condition
            return new SubArray(low, high, values[low]);
        } else {
            int mid = (int) (low + high) / 2;
            // Check left side
            SubArray leftSubArray = maxSubArray(values, low, mid);
            // Check right side
            SubArray rightSubArray = maxSubArray(values, mid + 1, high);
            // Check from middle
            SubArray crossSubArray = maxCrossSubArray(values, low, mid, high);
            // Compare left, right and middle arrays to find maximum sub-array
            if (leftSubArray.getSum() >= rightSubArray.getSum()
                    && leftSubArray.getSum() >= crossSubArray.getSum()) {
                return leftSubArray;
            } else if (rightSubArray.getSum() >= leftSubArray.getSum()
                    && rightSubArray.getSum() >= crossSubArray.getSum()) {
                return rightSubArray;
            } else {
                return crossSubArray;
            }
        }
    }

    private static SubArray maxCrossSubArray(int[] values, int low, int mid,
            int high) {
        int sum = 0;
        int maxLeft = low;
        int maxRight = high;

        int leftSum = Integer.MIN_VALUE;
        for (int i = mid; i >= low; i--) {
            sum = sum + values[i];
            if (sum > leftSum) {
                leftSum = sum;
                maxLeft = i;
            }
        }

        sum = 0;
        int rightSum = Integer.MIN_VALUE;
        for (int j = mid + 1; j <= high; j++) {
            sum = sum + values[j];
            if (sum > rightSum) {
                rightSum = sum;
                maxRight = j;
            }
        }
        SubArray max = new SubArray(maxLeft, maxRight, (leftSum + rightSum));
        return max;
    }

    static class SubArray {

        private int start;

        private int end;

        private int sum;

        public SubArray(int start, int end, int sum) {
            super();
            this.start = start;
            this.end = end;
            this.sum = sum;
        }

        public int getStart() { return start; }

        public void setStart(int start) { this.start = start; }

        public int getEnd() { return end; }

        public void setEnd(int end) { this.end = end; }

        public int getSum() { return sum; }

        public void setSum(int sum) { this.sum = sum; }

        @Override
        public String toString() {
            return "SubArray [start=" + start + ", end=" + end + ", sum=" + sum + "]";
        }
    }

    public static final void main(String[] args) {
        int[] values = { 5, 15, -30, 10, -5, 40, 10 };
        System.out.println("Maximum sub-array for array"
            + Arrays.toString(values) + ": " + maxSubArray(values, 0, 6));
    }

}

输出

Maximum sub-array for array[5, 15, -30, 10, -5, 40, 10]: SubArray [start=3, end=6, sum=55]

解决方案可以从https://github.com/gosaliajigar/Programs/blob/master/src/recursion/MaximumSubArray.java下载

两个子阵列是

[1, 2, 3]

和 [4, 9] 不包括负数

这里的最大子数组是 [ 4, 5]

所以输出是9

这是代码

public class MaxSubArray{
static void sumM(int a[], int n){
    int s1 = Integer.MAX_VALUE;
    int k = Integer.MAX_VALUE;
    int sum = 0;
    int s2 = 0;
    for(int i=0;i<n;i++){

        if(a[i]<s1){
            if(a[i]<0){
                k = Math.min(a[i],s1);
            }
        }

        if(a[i]>k){
            sum+=a[i];
        }

        if(a[i]<k){
            if(a[i]<0){
                continue;
                
            }
            s2+=a[i];
        }

    }
        if(sum>s2){
            System.out.println(sum);
        }
        else{
            System.out.println(s2);
        }
    
     
}

    public static void main(String[] args){
        int a[] = {1,2,3,-7,4,5};

        int n = a.length;

        sumM(a,n);
    }

    
}
 public static int kadane(int[] A) {
        
    int maxSoFar = 0;
 
        
    int maxEndingHere = 0;
 
    // traverse the given array
    for (int i: A) {
         // update the maximum sum of subarray "ending" at index `i` (by adding the
         // current element to maximum sum ending at previous index `i-1`)
         maxEndingHere = maxEndingHere + i;
 
         // if the maximum sum is negative, set it to 0 (which represents
         // an empty subarray)
         maxEndingHere = Integer.max(maxEndingHere, 0);
 
         // update the result if the current subarray sum is found to be greater
         maxSoFar = Integer.max(maxSoFar, maxEndingHere);
     }
 
     return maxSoFar;
}

您需要对所有可能的子数组求和。 要做到这一点,你可以做这个代码

public static int maxSubsequenceSum(int[] X) {
    int max = 0;
    boolean max_init = false;
    int max_from=0;
    int max_to=0; // this is not included
    for (int i = 0; i < X.length; i++) {
        for (int j = i + 1; j < X.length + 1; j++) {
            int total = 0;
            for (int k = i; k < j; k++) {
                total += X[k];
            }
            if (total > max || !max_init){
                max = total;
                max_init = true;
                max_from = i;
                max_to = j;
           }
        }
    }
    for (int i=max_from;i<max_to;i++)
       System.out.print(X[i]+",");
    System.out.println();
    return max;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM