要求
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
- 这里有书上看到的,别人写的和我自己想到的,都记录一下吧,有四种方法。
实现
方法一 (最开始想到的)
-
时间复杂度 O(N2)
-
思路:遍历依次寻找最大值
public static int maxSubArray(int[] nums) {
int max=Integer.MIN_VALUE;
int sum;
for(int i=0;i<nums.length;i++) {
sum=0;
for(int j=i;j<nums.length;j++) {
sum+=nums[j];
if(sum>max) {
max=sum;
}
}
}
return max;
}
方法二(别人的代码,我自己琢磨了一下。)
-
时间复杂度 O(N)
-
思路:动态规划。
public static int maxSubArray(int[] nums) {
int max=Integer.MIN_VALUE;
int sum=0;
for(int num:nums) {
if(sum>0)
sum+=num;
else
sum=num;
max=Math.max(sum, max);
}
return max;
}
方法三(自己想到的,可能有问题。)
- 时间复杂度 O(N)
public static int maxSubArray(int[] nums) {
int res=nums[0];
for(int i=1;i<nums.length;i++) {
if(nums[i-1]>0)
nums[i]+=nums[i-1];
if(nums[i]>res)
res=nums[i];
}
return res;
}
方法四(算法导论中看到的一种思路)
- 分治思想
- 思路:三种情况:
- 最大子串在左边
- 最大子串在右边
- 最大子串穿过中间 mid
public static int maxSubArray(int[] nums) {
return side(nums,0,nums.length-1);
}
// 计算左、右子序列中最大和
public static int side(int []nums,int from ,int to) {
if(from>=to) {
int min=Math.min(from, to);
return nums[min];
}
int mid=(from+to)>>1;
int left_max=side(nums,from,mid);
int right_max=side(nums,mid+1,to);
int cross_max=cross(nums,from,to,mid);
if(left_max>=right_max&&left_max>=cross_max)
return left_max;
if(right_max>=left_max&&right_max>=cross_max)
return right_max;
return cross_max;
}
// 计算穿插的最大子序列最大和
public static int cross(int []nums,int from,int to,int mid) {
int left_max=nums[mid],right_max=nums[mid+1];
int sum=0;
for(int i=mid;i>=from;i--) {
sum+=nums[i];
if(sum>left_max) {
left_max=sum;
}
}
sum=0;
for(int i=mid+1;i<=to;i++) {
sum+=nums[i];
if(sum>right_max) {
right_max=sum;
}
}
return left_max+right_max;
}