思路一:暴力破解
外循环控制子序列的头,内循环控制子序列的尾
class Solution {
public int maxSubArray(int[] nums) {
int max=Integer.MIN_VALUE;
for(int i=0;i<nums.length;i++)
{
int sum=0;
for(int j=i;j<nums.length;j++)
{
sum += nums[j];
if(sum>max)
max=sum;
}
}
return max;
}
}
//下面这种调用了Math的max方法作为比较,上面用的是三元表示法
class Solution {
public int maxSubArray(int[] nums) {
if(nums.length==1)
return nums[0];
int max=Integer.MIN_VALUE;
for(int i=0;i<nums.length;i++)
{
int total=0;
for(int j=i;j<nums.length;j++)
{
total+=nums[j];
max=Math.max(total,max);
}
}
return max;
}
}
时间复杂度O(n^2)
空间复杂度O(1)
思路二 分治法(递归)
分治法的主要思想是:
1、将大问题分解成小问题,将所有的小问题解决,那么大问题即解决
2、子问题的求解思路和大问题思路相同
3、存在终止条件
和常规的分治不同,常规是不断的一分为二,这是一分为三
下面的图解可以结合代码理解,最好是先把https://mp.csdn.net/mp_blog/creation/editor/118756766中的分治解法捋捋清楚,好家伙这两道题看了两天
重点是理解“跨越中间”的子序列
解释上图:向左边找最大子序列-2=(-3+1)
代码实现如下:
class Solution {
public int maxSubArray(int[] nums) {
return getMax(nums,0,nums.length-1);
}
//寻找最大子序列的和的函数
public int getMax(int[] arrs,int left,int right)
{
if(left==right)
return arrs[left];
int mid=left+(right-left)/2;
int leftMax=getMax(arrs,left,mid);//左递归
int rightMax=getMax(arrs,mid+1,right);//右递归
int crossMax=crossMax(arrs,left,right);//中间最大子序列
return Math.max(leftMax,Math.max(crossMax,rightMax));//左右中作比较然后返回
}
//中间最大子序列的和
public int crossMax(int[] arrs,int left,int right)
{
int mid=left+(right-left)/2;
int leftSum=arrs[mid];
int leftMax=leftSum;
//找中间的左边最大子序列的和
for(int i=mid-1;i>=left;i--)
{
leftSum += arrs[i];
leftMax=leftSum>leftMax?leftSum:leftMax;
}
int rightSum=arrs[mid+1];
int rightMax=rightSum;
//找中间的右边最大子序列的和
for(int i=mid+2;i<=right;i++)
{
rightSum += arrs[i];
rightMax=rightSum>rightMax?rightSum:rightMax;
}
//中间子序列分为“中间往左”的最大子序列和“中间往右”的最大子序列,左右的和即为中间最大子序列
return leftMax+rightMax;
}
}
【自己看的总结:一定不要被绕进去,分析终止条件以及只分析这一层与下一层两层的关系,当左边的递归到底第一次返回,右边的递归开始,接着又到右边的左递归,整个过程left、right、mid是一直改变的】