概念
什么是贪心算法?
贪心的本质 是选择每一阶段的局部最优解, 从而达到全局最优。
分饼干
核心思路
找出每一阶段的局部最优解, 这道题中, 有两种局部最优解, 都从最小的开始, 最小的饼干喂给胃口最小的孩子. 要么最大的饼干喂给最大胃口的孩子
-
题解 最大喂最大
javapublic int findContentChildren(int[] g, int[] s) { Arrays.sort(g); Arrays.sort(s); int i = g.length - 1; int j = s.length - 1; int count = 0; while (i >= 0 && j >= 0) { if (g[i] <= s[j]) { count++; i--; j--; } else { i--; } } return count; } -
最小喂最小
javapublic int findContentChildren(int[] g, int[] s) { Arrays.sort(g); Arrays.sort(s); int i = 0; int j = 0; int count = 0; while (i < g.length && j < s.length) { if (g[i] <= s[j]) { count++; i++; } j++; } return count; }
摆动序列
核心思路
- 可以将这个算法题, 理解为每一小段序列中, 找到波峰和波谷
- 如果是平峰, 那么如果平峰前面的preDiff>0, 那么就相当于上一个节点是波峰, 下一个curDiff必须<0才行. 所以 preDiff >= 0 and curDiff < 0
- 如果平峰前面的preDiff < 0, 那就相当于上一个节点是波谷, 下一个curDiff必须>0才行. 所以 preDiff <= 0 and curDiff > 0
题解
-
普通贪心算法思路
javapublic int wiggleMaxLength(int[] nums) { if (nums.length <= 1) { return nums.length; } if (nums.length == 2) { return nums[0] != nums[1] ? 2 : 1; } int preDiff = nums[1] - nums[0]; int count = 2; for (int i = 2; i < nums.length; i++) { int diff = nums[i] - nums[i - 1]; if (diff > 0 && preDiff <= 0 || diff < 0 && preDiff >= 0) { count++; preDiff = diff; } } return count; } -
动态规划思路(第一次接触, 有点难理解, 借助ai才勉强理解了, 等后面复习吧)
javapublic int wiggleMaxLength1(int[] nums) { if (nums.length <= 1) { return nums.length; } // dp[i][0] 表示 截止到i 的序列, i作为波峰最长摆动序列的长度, dp[i][1] 表示 截止到i 的序列, i作为波谷最长摆动序列的长度 int[][] dp = new int[nums.length][2]; dp[0][0] = dp[0][1] = 1; for (int i = 1; i < nums.length; i++) { dp[i][0] = dp[i][1] = 1; for (int j = 0; j < i; j++) { if (nums[i] > nums[j]) { // i 是 波峰, j是波谷, 那么i作为波峰的最大摇摆序列长度, = j的波谷最大摇摆序列长度 + 1 dp[i][0] = Math.max(dp[i][0], dp[j][1] + 1); } if (nums[i] < nums[j]) { // i 是 波谷, j是波峰, 那么i作为波谷的最大摇摆序列长度, = j的波峰最大摇摆序列长度 + 1 dp[i][1] = Math.max(dp[i][1], dp[j][0] + 1); } } } return Math.max(dp[nums.length - 1][0], dp[nums.length - 1][1]); }
最大子序和
核心思路
-
这道题贪心的点在与, 如果sum < 0, 那么再+=sum只会变小, 所以直接舍弃sum, sum=当前值, 重新计数
javapublic int maxSubArray(int[] nums) { int sum = nums[0]; int max = nums[0]; for (int i = 1; i < nums.length; i++) { if (sum > 0) { sum = sum + nums[i]; } else { sum = nums[i]; } max = Math.max(sum, max); } return max; } -
动态规划
-
以下是输入 nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] 的具体计算过程:
步骤分解
索引 i nums[i] 计算 dp[i] = Math.max(nums[i], dp[i-1] + nums[i]) dp[i] 结果 当前最大值 max 解释 0 -2 (初始赋值) -2 -2 以 -2 结尾,只能是 [-2] 1 1 max(1, -2 + 1) 1 1 1 比 -1 大,决定"自立门户" 2 -3 max(-3, 1 + (-3)) -2 1 -2 比 -3 大,选择"加入队伍" 3 4 max(4, -2 + 4) 4 4 4 比 2 大,决定"自立门户" 4 -1 max(-1, 4 + (-1)) 3 4 3 比 -1 大,选择"加入队伍" 5 2 max(2, 3 + 2) 5 5 5 比 2 大,选择"加入队伍" 6 1 max(1, 5 + 1) 6 6 6 比 1 大,选择"加入队伍" 7 -5 max(-5, 6 + (-5)) 1 6 1 比 -5 大,选择"加入队伍" 8 4 max(4, 1 + 4) 5 6 5 比 4 大,选择"加入队伍" javapublic int maxSubArray(int[] nums) { // dp[i] 表示以i为结尾的子数组的最大和 int[] dp = new int[nums.length]; int max = nums[0]; dp[0] = nums[0]; for (int i = 1; i < nums.length; i++) { dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]); max = Math.max(max, dp[i]); } return max; } -