My code:
public class Solution {
public int maxSubArray(int[] nums) {
if (nums == null || nums.length == 0)
return 0;
else if (nums.length == 1)
return nums[0];
int maxSum = nums[0];
int currSum = nums[0];
for (int i = 1; i < nums.length; i++) {
currSum = currSum >= 0 ? currSum + nums[i] : nums[i];
maxSum = Integer.max(maxSum, currSum);
}
return maxSum;
}
}
My test result:
![](http://upload-images.jianshu.io/upload_images/161212-fd9cf6a95e234da4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这道题目不算很难,但我知道我一定会想复杂。所以在动手痛苦得设置状态机之前还是决定看下别人的思路吧。否则又是乱写,浪费时间。靠if语句做出答案。思维是垃圾的。
其实面对这种,求 max of sub array 的题目,我每次一看到题,都会一种误解,需要求出这个最大值,方法是,找出求得这个最大值的区域范围。
其实完全不需要。我们只需要求最大值。那么,最大值可以不断刷新,当新的更大的值出现的时候,就将maxSum刷新。而不需要记录这个刷新值的起点和尾点是哪里。
于是只需要考虑一种情况。
当 currSum < 0 时,此时后一个值加上 currSum ,总sum都会变小。
所以直接将 currSum = nums[i]
如果 nums[i] <= 0 , 那么,也许,原 currSum 是要大于 此时的currSum的。
但那又如何呢?currSum保存的只是现在的和。而最大和,是保存在 maxSum里面的。
所以只需要比较下原maxSum 和 现currSum 大小即可。取最大值。
如果 nums[i] > 0, 那么此刻,因为 currSum <= 0 ,所以
currSum + nums[i] <= nums[i] 的。所以可以从nums[i] 重新开始,不需要加上之前的负数。
如果原currSum > 0 ,那就直接加上 nums[i], 不断与maxSum比较,不断刷新maxSum即可。
**
总结: Array, DP。 求 sub array 的最大和。记住,只需要求出最大和,而不需要考虑任何有关该最大和起止点的问题。
**
Anyway, Good luck, Richardo!
My code:
public class Solution {
public int maxSubArray(int[] nums) {
if (nums == null || nums.length == 0)
return 0;
int tracker = nums[0];
int max = nums[0];
for (int i = 1; i < nums.length; i++) {
tracker = Math.max(tracker + nums[i], nums[i]);
max = Math.max(max, tracker);
}
return max;
}
}
刚做完 maximum subarray product,
http://www.jianshu.com/p/e1456b90c819
所以这道题做起来比较快。
差不多的思路,用一个tracker去追踪之前最大的和,必须与现在这个index相连。然后,再综合找出最大值。
Anyway, Good luck, Richardo!
一开始也是直接拿O(n) 方法做的,后来看到有 divide and conquer做法,就看了解释,然后自己写了一遍。
```java
public class Solution {
public int maxSubArray(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
return helper(nums, 0, nums.length - 1);
}
private int helper(int[] nums, int left, int right) {
if (left == right) {
return nums[left];
}
int middle = left + (right - left) / 2;
int leftMax = helper(nums, left, middle);
int rightMax = helper(nums, middle + 1, right);
int leftPart = Integer.MIN_VALUE;
int temp = 0;
for (int i = middle; i >= left; i--) {
temp += nums[i];
leftPart = Math.max(leftPart, temp);
}
int rightPart = Integer.MIN_VALUE;
temp = 0;
for (int i = middle + 1; i <= right; i++) {
temp += nums[i];
rightPart = Math.max(rightPart, temp);
}
int crossMax = leftPart + rightPart;
return Math.max(crossMax, Math.max(leftMax, rightMax));
}
}
只不过觉得好没意思。。。太不自然的想法了,速度也很慢。
Anyway, Good luck, Richardo!
如果问,找出这个sub array 的途径:
My code:
public int[] maxSubArrayPath(int[] nums) {
if (nums == null || nums.length == 0) {
return null;
}
int max = nums[0];
int sum = nums[0];
int begin = 0;
int end = 0;
int currBegin = 0;
int currEnd = 0;
for (int i = 1; i < nums.length; i++) {
if (sum + nums[i] >= nums[i]) {
sum += nums[i];
currEnd = i;
}
else {
sum = nums[i];
currBegin = i;
currEnd = i;
}
if (max < sum) {
begin = currBegin;
end = currEnd;
max = sum;
}
}
return new int[]{begin, end};
}
如果问,找出不大于 k 的最大sub array 和
My code:
public int maxSubArrayK(int[] nums, int k) {
int n = nums.length;
int[] sums = new int[n];
int temp = 0;
TreeSet<Integer> set = new TreeSet<Integer>();
for (int i = 0; i < nums.length; i++) {
temp += nums[i];
sums[i] = temp;
set.add(temp);
}
set.add(0);
int max = Integer.MIN_VALUE;
for (int i = 0; i < nums.length; i++) {
Integer num = set.ceiling(nums[i] - k);
if (num != null) {
max = Math.max(max, nums[i] - num);
}
}
return max == Integer.MIN_VALUE ? -1 : max;
}
Anyway, Good luck, Richardo! — 09/24/2016