53.最大子数组和
方法一:Kadane's Algorithm(卡登算法 / 最大子数组和算法)
动态规划DP + 贪心
贪心:眼前好就留,不好就扔,只看眼前 1 步
动态规划:用前面算过的结果,推现在的结果,看前面所有步
比较:贪心看眼前,DP 看全局。
核心思想:如果前面的和是负数,就直接扔掉,从当前数重新开始。负数只会拖累后面的数,不可能让总和变大。
class Solution {
public int maxSubArray(int[] nums) {
int current = 0;
int max=nums[0];
for(int num: nums){
if(current<0) current=0;
current+=num;
if(current > max) max=current;//这一句等价于max = Math.max(max, current);
}
return max;
}
}
//只遍历数组 1 次
//时间复杂度:O(n)
方法二:暴力枚举(超时了无法ac)
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int max = nums[0]; // 先存第一个数当最大值
// 枚举所有起点 i
for (int i = 0; i < n; i++) {
// 枚举所有终点 j(j >= i)
for (int j = i; j < n; j++) {
// 计算从 i 到 j 的和
int sum = 0;
for (int k = i; k <= j; k++) {
sum += nums[k];
}
// 如果更大,就更新 max
if (sum > max) {
max = sum;
}
}
}
return max;
}
}
//三层循环,时间复杂度 O(n³)
//数组长度 100 就要跑 100×100×100 = 100 万次
//题目给 n=1e5,暴力会直接超时,跑不出来
知识点
Java Math 类常用方法(直接用,不用导包)
-
取最大、最小
Math.max(a, b) → 取大的 Math.min(a, b) → 取小的
Math.max(3, 5); // 5 Math.min(3, 5); // 3 -
绝对值
Math.abs(x)
Math.abs(-5); // 5 Math.abs(-99); // 99 -
平方根
Math.sqrt(x)
Math.sqrt(16); // 4.0 -
次方
Math.pow(a, b) a 的 b 次方
Math.pow(2, 3); // 8.0 -
随机数
Math.random() 返回 0.0 ~ 1.0 之间的随机小数
(int)(Math.random() * n);//生成 0 ~ n-1 的随机整数: