最大子数组
暴力求解法 时间复杂度O(n^3)
暴力枚举,时间复杂度O(n3)
1、找出子数组的最左端点 for i<- 1 to n
2、找出子数组的最右端点 for j<- i to n
3、求和,找出最大值
sum = nums[i] +……+nums[j]; ans = max(ans, sum)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
28public class Solution {
/**
* @param nums: A list of integers
* @return: A integer indicate the sum of max subarray
*/
public int maxSubArray(int[] nums)
{
int n=nums.length;
int max=nums[0],sum;
for(int i=0;i<n;i++)//找出子数组的最左端点
{
for(int j=i;j<n;j++)//找出子数组的最右端点
{
sum=0;
for(int k=i;k<=j;k++)
{
sum+=nums[k];
if(sum>=max)
max=sum;
}
}
}
return max;
}
}
时间复杂度O(n3) 求和操作被执行了很多次,有很多是重复计算的。
优化枚举 时间复杂度O(n^2)
算是半个暴力吧
原理:左端点相同的子数组,随着长度的增加,排在前面的元素被不断重复相加。如果我们记录下之前的求和结果,
就不需要对前面的元素再进行计算,比上面的少了一重循环。
1 | public static int maxSubArray(int[] nums) |
动态规划 时间复杂度O(n)
【只有子数组“前半部分”的和为正数时,子数组的求和才有可能最大】,在这个trick条件下,只需要遍历一次数组就可以。算法是:当从头开始遍历的元素的求和为正数时,继续向后遍历。当求和为负数时,重新开始计算求和,子数组的开始重置为下一个元素。
即对于任意一个子数组和,如果大于0,那么它再添加一个数,他的贡献是正值,如果子数组和小于0,再添加一个数,它的贡献则为负值,这时候不如将当前子数组舍掉,新数成为一个新数组。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
31package a;
public class Solution {
/**
* @param matrix
* : matrix, a list of lists of integers
* @param target
* : An integer
* @return: a boolean, indicate whether matrix contains target
*/
public static int maxSubArray(int[] nums)
{
if(nums==null||nums.length==0)
throw new IllegalArgumentException("array is null or empty.");
int n=nums.length;
int max=Integer.MIN_VALUE;
int sum=0;
for(int i=0;i<n;i++)//找出子数组的最左端点
{
sum=sum<0?nums[i]:sum+nums[i];
if(sum>max)
max=sum;
}
return max;
}
public static void main(String[] args) {
int maxSum = maxSubArray(new int[]{-100, -3, -10, -1, -7, -2, -5});
System.out.println(maxSum);
}
}
其实虽然原题中指出数组里有正数和负数,经过实践和思考,这个算法同样适用于全是正数,或者全是负数的情况。当全为正数时,最大的和自然就是所有元素的和,当全为负数时,最大和自然就是其中最大的那个负数的值。通过此算法都能得到相应的结果。
最小子数组
1 | public class Solution { |
可参考
https://blog.csdn.net/wwe4023/article/details/72953559
http://www.cnblogs.com/theskulls/p/4886531.html