力扣剑指Offer 第9天 动态规划(中等) 剑指 Offer 42. 连续子数组的最大和 剑指 Offer 47. 礼物的最大价值
剑指 Offer 42. 连续子数组的最大和
题目
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例 1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
提示 :
1 <= arr.length <= 10^5
-100 <= arr[i] <= 100
题解
动态规划
遍历数组,记录前n-1项和sumLast
与 前n项和sumCur
,维护当前最小非正数的前n项和min
与当前最大连续数组和maxSubSum
- 将0号位的数据设置为第1项的前一项和
sunLast
的值,同时设置为当前最大连续数组和maxSubSum
的值 - 如果0号位数据小于0则设置其为 当前最小非正数的前n项和
min
,否则设置min=0
- 从1号位开始遍历数组
- 前n项和
sumCur
=前n-1项和sumLast
+当前项的值nums[i]
- 维护当前最大连续数组的和
maxSubSum=Math.max(maxSubSum,sumCur-min)
- 维护当前最小非正数的前n项和
min=Math.min(min,sumCur)
- 更新前n-1项的和
sumLast=sumCur
class Solution {
public int maxSubArray(int[] nums) {
//-2 1 -3 4 -1 2 1 -5 4 原数组
//-2 -1 -4 0 -1 1 2 -3 1 前n项和
//-2 1 -2 4 3 5 6 1 5 最大连续数组和(前n项和-当前最小值)记录最大连续数组和
int min,maxSubSum=nums[0],sumCur,sumLast=nums[0];
min=nums[0]<0?nums[0]:0;
for(int i=1;i<nums.length;i++){
sumCur=sumLast+nums[i];
maxSubSum=Math.max(maxSubSum,sumCur-min);
min=Math.min(min,sumCur);
sumLast=sumCur;
}
return maxSubSum;
}
}
剑指 Offer 47. 礼物的最大价值
题目
在一个m*n
的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例 1:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
提示:
0 < grid.length <= 200
0 < grid[0].length <= 200
题解
动态规划
遍历整个数组,将值改成到该格的最大价值
- 先遍历第0行与第0列(最大值为前一个的最大值加本身)
- 从(1,1)开始一行行的遍历,
max=self+max(left,up)
self自身 left左边格子的最大值 up上方格子的最大值 - 输出右下角格子的值
grid[rows-1][cols-1]
class Solution {
public int maxValue(int[][] grid) {
//直接从左上角到右下角遍历维护到该格子的最大价值
//先计算第一行与第一列的最大价值 如何再去遍历其他格子
int rows=grid.length,cols=grid[0].length;
for(int r=1;r<rows;r++)grid[r][0]+=grid[r-1][0];
for(int c=1;c<cols;c++)grid[0][c]+=grid[0][c-1];
for(int r=1;r<rows;r++){
for(int c=1;c<cols;c++){
grid[r][c]+=Math.max(grid[r-1][c],grid[r][c-1]);
}
}
return grid[rows-1][cols-1];
}
}