文章

LeetCode Maximum Subarray

Problem

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [-2,1,-3,4,-1,2,1,-5,4], the contiguous subarray [4,-1,2,1] has the largest sum = 6.

click to show more practice.

More practice: If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

题目的意思是求一个数组,最大子序列的和。 并且,额外要求,在O(n)算法之外,可以尝试用分治法解决该问题。

Java 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.coderli.leetcode.algorithms.easy;

/**
 * Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
 * <p>
 * For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
 * the contiguous subarray [4,-1,2,1] has the largest sum = 6.
 *
 * @author OneCoder 2017-10-31 23:41
 */
public class MaximumSubarray {

    public static void main(String[] args) {
        MaximumSubarray maximumSubarray = new MaximumSubarray();
        System.out.println(maximumSubarray.maxSubArray(new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4}));
        System.out.println(maximumSubarray.maxSubArray(new int[]{-2, -1}));
        System.out.println(maximumSubarray.maxSubArray(new int[]{1, -3, 2}));
        System.out.println(maximumSubarray.maxSubArray(new int[]{1, -1, -2, 2}));
        System.out.println(maximumSubarray.maxSubArrayByDC(new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4}));
        System.out.println(maximumSubarray.maxSubArrayByDC(new int[]{-2, -1}));
        System.out.println(maximumSubarray.maxSubArrayByDC(new int[]{1, -3, 2}));
        System.out.println(maximumSubarray.maxSubArrayByDC(new int[]{1, -1, -2, 2}));
    }

    public int maxSubArray(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int maxResult = nums[0];
        int tempSum = maxResult;
        for (int i = 1; i < nums.length; i++) {
            if (tempSum <= 0) {
                tempSum = nums[i];
            } else {
                tempSum = tempSum + nums[i];
            }
            if (tempSum > maxResult) {
                maxResult = tempSum;
            }
        }
        return maxResult;
    }

    public int maxSubArrayByDC(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        return findMaxSubArray(nums, 0, nums.length - 1);

    }

    private int findMaxSubArray(int[] nums, int from, int to) {
        if (from == to) {
            return nums[from];
        }
        int mid = from + (to - from) / 2;
        int maxLeft = findMaxSubArray(nums, from, mid);
        int maxRight = findMaxSubArray(nums, mid + 1, to);

        int midLeftMax = nums[mid];
        int midLeftTempSum = midLeftMax;
        for (int i = mid -1; i >= from; i--) {
            midLeftTempSum += nums[i];
            if (midLeftMax < midLeftTempSum) {
                midLeftMax = midLeftTempSum;
            }
        }

        int midRightMax = nums[mid];
        int midRightTempSum = midRightMax;
        for (int i = mid + 1; i <= to; i++) {
            midRightTempSum += nums[i];
            if (midRightMax < midRightTempSum) {
                midRightMax = midRightTempSum;
            }
        }

        int midMax = midLeftMax + midRightMax - nums[mid];
        if (maxLeft >= maxRight && maxLeft >= midMax) {
            return maxLeft;
        } else if (maxRight > midMax) {
            return maxRight;
        } else {
            return midMax;
        }
    }
}


分析

解法1是一个线性解法,好处是效率够快,不足就是丢失最大子序列的位置信息,最后得到的仅仅是个最大值。

解法2,就是题目要求尝试的分治解法。即把子序列可能存在位置分三种情况考虑,左、右和横跨中点。 对于左和右,可以递归解决。横跨的简单计算即可。

本文由作者按照 CC BY 4.0 进行授权