https://leetcode-cn.com/problems/maximum-subarray/description/
我的解决方案:这就道破题,我做了一个通宵。。。如果看不懂代码,可以看一下我下面的思路变迁,都是一点一点想出来的
class Solution {
public static int getRes3(int[] nums, int maxRes) {
maxRes=Integer.max(nums[0], maxRes);
maxRes=Integer.max(nums[2], maxRes);
maxRes=Integer.max(nums[0]+nums[1]+nums[2], maxRes);
return maxRes;
}
public static int getRes5(int[] nums, int maxRes) {
maxRes = Integer.max(nums[0]+nums[1]
+nums[2]+nums[3]+nums[4], maxRes);
maxRes = Integer.max(nums[0]+nums[1]+nums[2], maxRes);
maxRes = Integer.max(nums[2]+nums[3]+nums[4], maxRes);
maxRes = Integer.max(nums[0], maxRes);
maxRes = Integer.max(nums[2], maxRes);
return Integer.max(nums[4], maxRes);
}
public static int recursion(int[] nums, int len, int maxRes) {
if(len==3)
return getRes3(nums, maxRes);
if(len==5)
return getRes5(nums, maxRes);
if(nums[0]+nums[1]<=0)
maxRes = Integer.max(nums[0], maxRes);
else {
nums[2]+=nums[0]+nums[1];
maxRes = Integer.max(nums[0], maxRes);
}
if(nums[len-2]+nums[len-1]<=0)
maxRes = Integer.max(nums[len-1], maxRes);
else {
nums[len-3]+=nums[len-1]+nums[len-2];
maxRes = Integer.max(nums[len-1], maxRes);
}
int cnt=0;
for(int i=2;i<len-2;i++) {
nums[cnt++]=nums[i];
}
return recursion(nums, cnt, maxRes);
}
public static int maxSubArray(int[] nums) {
boolean flag = false;
for(int i=0;i<nums.length;i++) {
if(nums[i]>0) {
flag = true;
break;
}
}
if(flag==false) {
int max = Integer.MIN_VALUE;
for(int i=0;i<nums.length;i++)
if(nums[i]>max) max=nums[i];
return max;
}
int head=0;
for(int i=0;i<nums.length;i++) {
if(nums[i]>0) {
head = i;
break;
}
}
int lenDec=0;
for(int i=nums.length-1;i>=0;i--) {
if(nums[i]>0) break;
lenDec++;
}
int numLen = nums.length-lenDec;
int cnt=0;
int sum=nums[head];
for(int i=head+1;i<numLen;i++) {
//此处不能使用nums[i]来判断符号,因为0会把负数也弄到sum中
while(sum*nums[i]>=0) {
sum+=nums[i];
i++;
if(i==numLen) break;
}
if(i==numLen) break;
nums[cnt++]=sum;
//跳出了while循环,说明符号发生了改变
sum=nums[i];
}
nums[cnt++] = sum;
int maxRes = Integer.MIN_VALUE;
if(cnt==1)
return nums[0];
return recursion(nums, cnt, maxRes);
}
public static void main(String[] args) {
int[] test = new int[] {-9,9,7,-8,-3,2,-9,1,7,-2,-9,7,-9,5,5,-3,9,0};
System.out.println(maxSubArray(test));
}
}
其实他就是一道水得不能再水的题:
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
int tempSum = 0;
for (int i = 0; i < nums.length; i++) {
if (tempSum < 0) {
tempSum = nums[i];
} else {
tempSum += nums[i];
}
max = Math.max(tempSum, max);
}
return max;
}
}
我的内心是崩溃的。。。。。
我的思路:
package ads;
import java.text.Normalizer.Form;
class AlarmClock {
public static void main(String args[]) {
最长连续字串的难点在于,如何确定前后指针的移动
为了消除干扰,我们会预处理数组,先处理掉不含正数的数组
设置两个指针,front和rear,分别指向连续子串的首位
向后拓展,当后和lSum值为正时,或者nums[index]>sum;
将rear更新为当前index
再来更新front值:
Form head to rear : index
rSum+=nums[head]+nums[index];
当前和非正时,就需要更新head值了
if(!(rSum>0))
head=index;
}
}
产生了一个Idea,把数组分成一块一块的,
正负交织
然后再进行组合
如果开头是负数,那就全部扔掉
这样一来,数组就会越变越小
eg:
-2,1,-3,4,-1,2,1,-5,4
==> 1 -3 4 -1 3 -5 4
如果两者相加相较于单独比较大,那么就有必要相加 我们处理完的数组的长度总是奇数
1 2 3 4 5 6 7 8 9
正负正负正负正负正
我们的数组都应该是上面的这种形式,首位都不会存在负数
if(nums[1]+nums[2]+nums[3]>nums[1]&&nums[1]+nums[2]+nums[3]>nums[3])
nums[3]=nums[1]+nums[2]+nums[3];
head = 3;
else
如果出现这种情况,就说明中间的那个负数的绝对值比较大,比左侧或右侧大
if(左侧小于右侧)
则1,2被抛弃
否则
nums[1]称为一个候选结果res
head=3;
789还是同样的道理,更新新的rear
如果else
nums[9]比nums[7]大且大于nums[1](res),则nums[9]称为候选结果
我们有一个任务就是确定123什么时候该合并,什么时候不该合并
很明显if(1+2<=0) 不该合并 1作为单独候选结果存在
else 合并 1同样还是作为候选结果单独存在
head = 3;
之所以要把1作为候选结果,是因为我们要考虑极端情况,2是一个很大的负数,这时候1可能就是一个很大的正数 而345678之和也不及1自己的值
因此我们不能轻易就把1抛弃
这是一个从两边向中间合并的过程
我们可以使用递归,每次处理123和789 首3和尾3 并比较出较大的后选结果
候选结果挨个比较,筛选出最大的候选结果作为返回值
int recursion(int[] nums, int len, int maxRes);
当数组长度为5的时候,即可比较出最大值
1 2 3 4 5
对1+2+3+4+5
1+2+3
3+4+5
1
3
5进行比较
public class Solution {
public static int maxSubArray(int[] nums) {
boolean flag = false;
for(int i=0;i<nums.length;i++) {
if(nums[i]>0) flag = true;
}
if(flag==false) {
int min = Integer.MIN_VALUE;
for(int i=0;i<nums.length;i++)
if(nums[i]>min) min=nums[i];
return min;
}
int front = 0;
int rear = 0;
int sum=0,rSum=0,lSum=0;
for(int i=0;i<nums.length;i++) {
if(nums[i]>0) {front=i;rear=i;rSum=nums[i];break;}
}
sum=rSum;
if(rear==nums.length-1) return nums[front];
//我当前的处理办法,只能是走一步停一步,一气呵成会产生问题
//front的处理会出现错误,rear倒是没什么问题
while(flag) {
for(int i=rear+1;i<nums.length;i++) {
if(i==nums.length-1) flag=false;
lSum+=nums[i];
//有一种致命的情况,我没有考虑到,就是后和为0,但是在后和中存在一个比sum更大的值
//因此,我要在每次while循环的末尾求出sum值,然后在本for循环中比较nums[index]和sum的大小
//如果nums[index]更大,直接更新rear值
if(lSum>0) {rear = i; lSum=0;break;}
if(nums[i]>sum) {rear=i;}
//应该清空lSum值,把负值扔掉
lSum=0;
}
for(int i=front+1;i<rear;i++) {
rSum+=nums[i];
if(!(rSum>0)) {
front=i ;
rSum=nums[front];
}
}
rSum=nums[front];
if(!(rSum>0)) { front+=1;rSum=nums[front];}
sum=0;
for(int i=front;i<=rear;i++) {
sum+=nums[i];
}
}
sum=0;
for(int i=front;i<=rear;i++) {
sum+=nums[i];
}
return sum;
}
public static void main(String[] args) {
int[] test = new int[] {2,-1,3,-1};
System.out.println(maxSubArray(test));
}
}