代码随想录算法Day31 | 455.分发饼干 ,376. 摆动序列 ,53. 最大子序和
455.分发饼干
题目链接:455. 分发饼干 - 力扣(LeetCode)
思路
这里的局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。
也可以换一个思路,小饼干先喂饱小胃口。
代码
1 class Solution { 2 // 思路1:优先考虑饼干,小饼干先喂饱小胃口 3 public int findContentChildren(int[] g, int[] s) { 4 Arrays.sort(g); 5 Arrays.sort(s); 6 int start = 0; 7 int count = 0; 8 for (int i = 0; i < s.length && start < g.length; i++) { 9 if (s[i] >= g[start]) { 10 start++; 11 count++; 12 } 13 } 14 return count; 15 } 16 }
1 class Solution { 2 // 思路2:优先考虑胃口,先喂饱大胃口 3 public int findContentChildren(int[] g, int[] s) { 4 Arrays.sort(g); 5 Arrays.sort(s); 6 int count = 0; 7 int start = s.length - 1; 8 // 遍历胃口 9 for (int index = g.length - 1; index >= 0; index--) { 10 if(start >= 0 && g[index] <= s[start]) { 11 start--; 12 count++; 13 } 14 } 15 return count; 16 } 17 }
376. 摆动序列
题目链接:376. 摆动序列 - 力扣(LeetCode)
思路

首先可以将题目给的数据画出如上的波峰图,根据图中可知:
局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。
整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。
在实际操作可以设置一个遍历记录峰值数量就可以了。
当用这思路解决该问题时要注意三个问题。
- 当仅有两个数字,当两个数字不相等时,是2个峰
- 当仅有一个数字时,是1个峰
- 当有N个数字,但是这N个数字值都相同时,也算1个峰
代码
1 class Solution { 2 public int wiggleMaxLength(int[] nums) { 3 if (nums.length <= 1) { 4 return nums.length; 5 } 6 //当前差值 7 int curDiff = 0; 8 //上一个差值 9 int preDiff = 0; 10 int count = 1; 11 for (int i = 1; i < nums.length; i++) { 12 //得到当前差值 13 curDiff = nums[i] - nums[i - 1]; 14 //如果当前差值和上一个差值为一正一负 15 //等于0的情况表示初始时的preDiff 16 if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) { 17 count++; 18 preDiff = curDiff; 19 } 20 } 21 return count; 22 } 23 }
1 // DP 2 class Solution { 3 public int wiggleMaxLength(int[] nums) { 4 // 0 i 作为波峰的最大长度 5 // 1 i 作为波谷的最大长度 6 int dp[][] = new int[nums.length][2]; 7 8 dp[0][0] = dp[0][1] = 1; 9 for (int i = 1; i < nums.length; i++){ 10 //i 自己可以成为波峰或者波谷 11 dp[i][0] = dp[i][1] = 1; 12 13 for (int j = 0; j < i; j++){ 14 if (nums[j] > nums[i]){ 15 // i 是波谷 16 dp[i][1] = Math.max(dp[i][1], dp[j][0] + 1); 17 } 18 if (nums[j] < nums[i]){ 19 // i 是波峰 20 dp[i][0] = Math.max(dp[i][0], dp[j][1] + 1); 21 } 22 } 23 } 24 25 return Math.max(dp[nums.length - 1][0], dp[nums.length - 1][1]); 26 } 27 }
53. 最大子序和
题目链接:53. 最大子数组和 - 力扣(LeetCode)
思路
暴力解法的思路,第一层for 就是设置起始位置,第二层for循环遍历数组寻找最大值。
而贪心的方法,从第一个数开始累加,如果当前和已经为负,那么加上下一个数,一定会使下一个数变小。所以出现这种情况时,直接舍弃这个数,从下一个数开始重新计算。
详细如图

代码
1 class Solution { 2 public int maxSubArray(int[] nums) { 3 if (nums.length == 1){ 4 return nums[0]; 5 } 6 int sum = Integer.MIN_VALUE; 7 int count = 0; 8 for (int i = 0; i < nums.length; i++){ 9 count += nums[i]; 10 sum = Math.max(sum, count); // 取区间累计的最大值(相当于不断确定最大子序终止位置) 11 if (count <= 0){ 12 count = 0; // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和 13 } 14 } 15 return sum; 16 } 17 }
1 // DP 方法 2 class Solution { 3 public int maxSubArray(int[] nums) { 4 int ans = Integer.MIN_VALUE; 5 int[] dp = new int[nums.length]; 6 dp[0] = nums[0]; 7 ans = dp[0]; 8 9 for (int i = 1; i < nums.length; i++){ 10 dp[i] = Math.max(dp[i-1] + nums[i], nums[i]); 11 ans = Math.max(dp[i], ans); 12 } 13 14 return ans; 15 } 16 }

浙公网安备 33010602011771号