Leetcode 53- 最大子段和

分治 or 动态规划

Posted by 刘知安 on 2019-10-30
文章目录
  1. Leetcode Leetcode 53- 最大子段和
    1. 1. 题目描述
    2. 2. 思路
      1. 2.1 分治
      2. 2.2 动态规划
    3. 3. 代码
      1. 3.1 分治求解
      2. 3.2 动态规划

Leetcode Leetcode 53- 最大子段和

1. 题目描述

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

1
2
3
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6

2. 思路

2.1 分治

这个没啥好说的,经典题,当时在算法书上印象比较深刻的就是用分治:

  1. 最大子段和在左半部分
  2. 最大子段和在右半部分
  3. 最大子段和横跨了左右,包含了mid对应的元素在内。

其中1和2中是会有明显的分治情况出现的,最后三个情况取最大,没什么好说的,时间复杂度为 O(n*logn),空间复杂度O(1)

2.2 动态规划

有意思的是,这题的题目上有这么一句话:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解.

What??? 原来分治不是最优解,居然也能AC。然后看了一下讨论区,我反正是不知道那群人在扯什么玩意儿。。我在百度上看到这么一段解释,清晰明了,上个图:

动态规划

动态规划

3. 代码

3.1 分治求解

战胜 30%

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
/**
* @ClassName MaxSubSequence
* @Deacription // TODO
* @Author LiuZhian
* @Date 2019-10-30 18:58
* @Version 1.0
**/

public class MaxSubSequence {
public int maxSubArray(int[] nums) {
// ① 分治法
return maxSub(nums, 0, nums.length - 1);

}
public int maxSub(int[] nums, int left, int right) {

// 思路是:分治求解. 以中间值为界限,可能出现下面3种情况:
// 1. 最大子段和在左边
// 2. 最大子段和在右边
// 3. 最大子段和横跨左右两段,用双指针求解即可

if (left == right) // 分治的边界情况
return nums[left];

int mid = (left + right) / 2;
int left_max = maxSub(nums, left, mid);
int right_max = maxSub(nums, mid + 1, right);

int cross_mid_left = 0; // 横跨中间的左半部分
int left_part_max = nums[mid];
for (int l = mid; l >= left; l--) {
cross_mid_left += nums[l];
if (cross_mid_left > left_part_max)
left_part_max = cross_mid_left;
}

int cross_mid_right = 0; // 横跨中间的左半部分
int right_part_max = nums[mid + 1];
for (int r = mid + 1; r <= right; r++) {
cross_mid_right += nums[r];
if (cross_mid_right > right_part_max)
right_part_max = cross_mid_right;
}

// 整体为左半部分最大+右半部分最大
int cross_mid_max = left_part_max + right_part_max;

// 返回3种情况的最大值
int max = cross_mid_max;
if (left_max > max)
max = left_max;
if (right_max > max)
max = right_max;

return max;
}

public static void main(String[] args) {
int[] nums = {-1};
MaxSubSequence m = new MaxSubSequence();
System.out.println(m.maxSubArray(nums));
}
}

3.2 动态规划

战胜 99.97%

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
/**
* @ClassName MaxSubSequence
* @Deacription // TODO
* @Author LiuZhian
* @Date 2019-10-30 18:58
* @Version 1.0
**/

public class MaxSubSequence {
public int maxSubArray(int[] nums) {
// ② 动态规划
if(nums.length==1)
return nums[0];

int[] c = new int[nums.length];
c[0] = nums[0];

for (int i = 1; i < nums.length; i++) {
if (nums[i] + c[i - 1] > nums[i])
c[i] = nums[i] + c[i - 1];
else
c[i] = nums[i];
}

int maxSubSum = c[0];
for (int i = 1; i < nums.length; i++)
if (c[i] > maxSubSum)
maxSubSum = c[i];
return maxSubSum;

}
public static void main(String[] args) {
int[] nums = {-1};
MaxSubSequence m = new MaxSubSequence();
System.out.println(m.maxSubArray(nums));
}

}