135.分发糖果
-
两个数组 + 两次遍历 ,取 最大峰值 ,准备两个数组 L 和 R ,默认填充 1 ,
-
先 从左往右 扫描一遍, 更新 L 数组,如果 右边 分数 > 左边 分数 , 那么就让 右边 比 左边 分的糖果 多1个 ,
-
再 从右往左 扫描一遍, 更新 R 数组, 如果 左边 分 数 > 右边 分数 , 那么 就让 左边 比 右边 分的糖果 多1个 ,
-
最后遍历一遍 数组长度,将 max(L[i], R[i]) 最大值 累加到结果 res 中 即可。
-
优化:可以使用 一个 数组 + 两次遍历 ,只使用一个 R 数组,外加一个 L 变量, R 数组跟上面一样的统计方式,而 L 变量 可以在计算更新答案的 for 循环中一并更新。
455. 分发饼干
-
排序 + 贪心 ,先用 尺寸小 的饼干来满足 胃口值小 的小孩,再用 尺寸大 的饼干来满足 胃口值大 的小孩,这样能尽量满足最多的孩子。
-
具体的,先将饼干数组和小孩数组分别 从小到大排序 ,然后遍历饼干数组,取出每一块饼干 j ,如果当前饼干大小 s[j] 大于等于 当前孩子的胃口 g[i] ,就让孩子指针 i++ 前进,否则孩子指针不动。
-
最后返回指针 i 的位置就是能满足的孩子数量。
605.种花问题
-
1. 哨兵前后补0 ,防御式编程思想:创建一个长度 N+2 的数组,在 flowerbed 数组两端各补一个 0 , 这样处理的好处在于不用考虑边界条件,
-
然后让 i 遍历 [1, N] , 只要 i 位置的前后连续出现 3 个 0 ,就可以在 i 位置栽上一棵花, n-- , 如果 n 减到 0 就可以栽完。
-
2. 贪心 ,遍历花坛的每个位置,在可以种花的地方就种一朵,能种就种(因为在任一种花时候,不种都不会得到更优解)
-
这里可以种花的条件是: 当前位置为空 && 当前位置左边为空 (或者 自己就是最左 ) && 当前位置右边为空 (或者 自己是最右 ),即当前 位置的前后连续出现 3 个 0 的 空位置。
665.非递减数列
-
分情况讨论,如果存在前后两个数 b 和 a 满足: b > a 即前面的数大于后面的数
-
1)如果此时 b 是第 0 个元素, a 是第 1 个元素,也就是说 b 前面没有数了,将 b 改成 a 即可
-
2)如果此时 b 的前面还有元素,记为 c , 如果 c <= a , 就把 b 改成 a ,如果 c > a , 就把 a 改成 b 即可
-
以上结论是经过各种情况总结得到,如果画图就会发现,实际上就是 把三者中较高的值向下拉平 ,或者 把三者中较低的值向上拉平 的过程。
-
计数修改的次数,超过 1 返回 false ,否则最后返回 true 。
具体可以分四种情况讨论:
下面总结一下上面的四种情况:
注意,这个结论并非是意味着这样改就可以让任意序列都能变成非递减序列,只是根据前面分析得出,这样已经是贪心的局部最优的解了(也就是说这个改法只是能够尽量让更多的情况满足非递减序列,而其他的改法都不如这个改法能满足的情况多)。
我觉得这个题属于非常难的题目了,因为最终这个代码的写法是要经过分情况讨论,总结出来的,这不是那种你会用某种数据结构或某种套路模板就能解决的。如果不是刷过这个题,很难想到只需要比较三个相邻的数就能解决这个问题。
12. 整数转罗马数字
-
贪心 ,把 整数数字 与 罗马数字 可能出现的所有情况和对应关系,放在 两个 数组 中,并且按照整数数字的大小 降序排列 ,
-
每次从 整数数组 中取一个 最大的数字 ,如果 总面值大于等于该数字 ,就从 总面值 中 减去该数字 ,同时从 罗马数字数组 中取一个对应面值的 字符串 拼接到结果中,不停的尝试减去这个数字并拼接,直到 总面值小于该数字 了,停止,继续从整数数组中取下一个较大的数字尝试。
-
注意:除了题目给出的七种字符对应关系外,还应该把题目提到的6种特殊情况的数字对应关系枚举出来。
注意,这里每次 for 循环中判断,如果 num 能够满足当前面值,则需要 while 循环不停的减去当前面值,而不能只减 1 次,因为我们要把最大面值优先用完,最大面值可以使用多次。(可以类比找零钱的过程,能给你一张一百元的纸币就绝不会给你一百个一块的硬币,除非没有一百的了)
13. 罗马数字转整数
-
1. 贪心 , 把 整数数字 与 罗马数字 可能出现的所有情况和对应关系,放在 两个 数组 中,并且按照整数数字的大小 降序排列 ,
-
每次从 罗马数字数组 中取一个 最大的面值 ,看字符串 s 开头 是否包含该面值 ,如果 包含 就累加对应的 整数数字 到结果 res 中 ,并从字符串 s 中移除该面值( substring ) ,不断重复尝试,直到字符串 s 开头不包含当前面值为止,继续从罗马数字数组中取下一个较大的面值尝试。
这题代码跟 12 题代码逻辑几乎类似,只是取面值的数组和用来拼接结果的数组刚好反过来了。
-
2. 两两进行比较 ,如果 左边的数 < 右边的数 ,就做 减法 ,否则做 加法 。
-
具体地,可以用一个 map 存储每个 罗马字符 对应的 整数 ,设 res 初始为 s[0] 对应的 整数 ,然后从 1 开始遍历字符串 s 的每个字符,
-
如果 s[i-1] 对应的整数 ≥ s[i] 对应的整数, 就把 s[i] 对应的整数累加到 res 中,
-
如果 s[i-1] 对应的整数 < s[i] 对应的整数, 就先从 res 中减去 s[i-1] 对应的整数,再累加 二者之差 , res - map[s[i-1]] + ( map[s[i]] - map[s[i-1]] ) , 如 IV , 先减去之前加的 I 再加上 V-I 。
1578. 使绳子变成彩色的最短时间
-
贪心 , 每当遇到与当前颜色相同的若干气球时,需要戳爆若干气球,最后只保留 1 个, 那自然是 保留 那个戳起来最费劲 花费时间最多 的气球,总代价才会最小。
-
具体的,遍历每一个字符,每次循环中判断 当前字符 是否跟 后面的字符 一样,设 allCost 表示 总花费,设 maxCost 表示 花费时间最多 的气球 花费 ,二者初始为 当前字符花费 ,
-
如果 当前字符 跟 后面的字符 一样,就一直循环累加后面重复字符的花费到 allCost 中,同时更新 maxCost 为遇到的重复字符花费的最大值,直到遇到后面跟当前不一样的,
-
然后 allCost - maxCost 就是这段重复字符中删除其他只保留一个的最低成本,累加到总结果 res 中,继续判断下一个字符。
这个题的本质其实就是找连续相同且相邻的字符中花费代价最高的字符,然后排除这个字符的花费,累加这一段的剩余的花费代价。 这个代码本身不算很难,但是难的是从题目的气球描述到这个问题的转换思想。(看到绳子、气球、彩色就会让人很懵,对问题的抽象能力很重要)
517. 超级洗衣机
-
贪心 ,首先,如果最后每台洗衣机的衣服数量相等的话, 显然 衣服总数必须是洗衣机数量的整数倍 。
-
用 所有的衣服数量 除以 洗衣机数量 得到 平均数avg ,遍历数组,用每个洗衣机的 衣服数量 减去 平均数 ,得到一个 差值diff , 表示需要 移入 或 移出 的数量,同时对 diff 进行累加,
-
将截止 machines[0..i] 的 diff 累加和记为diffSum , 把 i 及左侧 的洗衣机看成一组,记为 A ,剩余部分看成一组,记为 B , 显然 如果 A 的累加和为 正 ,就要从 A 移出衣服到 B 中,反之需要从 B 中移出衣服到 A 中。
-
因此答案就应该是每一步 abs(diffSum) 的最大值,但是这里需要修正一下,变成 max(abs(diffSum), diff) ,因为如果当前 i 上的衣服数量特别多时,除了需要移出衣服向左侧的组内填充外,还需要填充右侧的组,但是每次只能从 i 上移出 1 件,因此最多的步数就是 diff ,所以答案是每一步记录的max(abs(diffSum), diff)的最大值。
下图是三个例子的操作示意:
上面三个例子中:第一个例子最少需要操作 7 步,它是 diff 中的最大值;第二个例子中最少需要操作 3 步,它是 sum 中的最大绝对值;第三个例子最少需要操作 7 步,它是 diff 中的最大值。