例题一
解法(暴⼒解法 -> 贪⼼):
暴⼒解法:
a. 依次枚举所有的起点;
b. 从起点开始,模拟⼀遍加油的流程
贪⼼优化:
我们发现,当从 i 位置出发,⾛了 step 步之后,如果失败了。那么 [i, i + step] 这个区间内任意⼀个位置作为起点,都不可能环绕⼀圈。因此我们枚举的下⼀个起点,应该是 i + step + 1 。
例题二
解法(贪⼼):
假设我们有⼀个数 n,它有m位数字,每⼀位数字分别是 d1,d2,......,dm 。 我们想要修改这个数字,使得修改后的结果既⼩于原数字 n ,⼜满⾜单调递增和最⼤化。为了实现这个⽬标,我们需要将不满⾜递增的⾼位数字尽可能地减⼩。
⾸先,我们需要找到⼀个位置 k,使得 d 1 ≤ d 2 ≤...≤ d k > d k +1...(例如:12335412,k=4,d k=5)。这个位置 k 表⽰从⾼到低,第⼀个不满⾜单调递增的数字的位置。我们需要将这个数字减1,因为这是最⼩的减⼩量。
接下来,我们需要将低位数字都修改为9,这样可以保证修改后的数字是最⼤的,并且还能保证单调递增。修改后存在以下两种情况:
1. 如果d k −1 < dk ,则修改后的数字满⾜d 1 ≤ d 2 ≤ ... ≤ ( d k − 1) ≤ 9 ≤ ... ≤ 9 。这是因为 dk在减1的同时,低位数字被修改为 9。
2. 如果 d k −1 = dk,则修改后的数字满⾜ d 1 ≤ ... ≤ d k −1 > ( d k − 1) ≤ 9 ≤ ... ≤ 9。在这种情况下,我们仍然保证了低位数字的最⼤化和单调递增,但是可能会出现⾼位数字不再单调递增的情况。
2. 如果 d k −1 = dk,则修改后的数字满⾜ d 1 ≤ ... ≤ d k −1 > ( d k − 1) ≤ 9 ≤ ... ≤ 9。在这种情况下,我们仍然保证了低位数字的最⼤化和单调递增,但是可能会出现⾼位数字不再单调递增的情况。
第⼆种情况需要继续修改这个数字。我们需要找到⼀个位置 t ,使得d 1 ≤ d 2 ≤ ... < d t = d t +1 = ... = dk。这个位置 t 表⽰从⾼到低,最后⼀个⾼位数字相等的位置。我们需要将dt 减 1,并将之后的所有数字都修改为9,以满⾜d 1 ≤ d 2 ≤ ... ≤ d t − 1 ≤ 9 ≤ ... ≤ 9,即⾼位数字的单调递增和低位数字的最⼤化。
• 例如:1224444361,成功修改后的最⼤值为1223999999。
通过这种修改⽅式,我们可以得到⼀个新的数字,它既⼩于原数字 n,⼜满⾜单调递增和最⼤化。
算法思路:
1. 将整数 n 转换为字符串形式,以便于对其进⾏修改操作,并将其存储在字符串变量 str 中。
2. 初始化⼀个变量 pos,⽤于记录从⾼位到低位第⼀个不满⾜单调递增的数字的位置。初始值为 -1,表⽰在第⼀位之前。
3. 从⾼位到低位遍历字符串 str,寻找第⼀个不满⾜单调递增的数字的位置。当遇到⼀个数字⼩于前⼀个数字时,记录这个位置为 pos,并退出循环。
4. 如果 pos 被更新,说明存在需要修改的数字,执⾏以下操作:
a. 将 pos 位置后的所有数字修改为 9,这样可以保证修改后的数字是最⼤的。
b. 将 pos 位置的数字减⼀,因为这是最⼩的减少量,同时也能够保证修改后的数字仍然⼩于原数
字 n。
c. 检查 pos 前⼀位数字是否⼩于减⼀后的 pos 位置数字,如果⼩于,则说明在 pos 位置之前还有
相同的数字,需要将 pos 前⼀位数字减⼀,并将 pos 位置修改为 9。
i. 重复这个操作,直到 pos 前⼀位数字⼤于等于减⼀后的 pos 位置数字或 pos 已经移动到了第⼀位。
5. 将修改后的字符串 str 转换为整型数字并返回。
例题三
解法(贪⼼):
贪⼼策略:
正难则反:
当「反着」来思考的时候,我们发现:
i. 当 end <= begin 的时候,只能执⾏「加法」操作;
ii. 当 end > begin 的时候,对于「奇数」来说,只能执⾏「加法」操作;对于「偶数」来说,最好的⽅式就是执⾏「除法」操作这样的话,每次的操作都是「固定唯⼀」的。
例题四
解法(排序 + 贪⼼):
贪⼼策略:
a. 先按照区间的「左端点」排序:此时我们会发现,能够合并的区间都是连续的;
b. 然后从左往后,按照求「并集」的⽅式,合并区间。
如何求并集:
由于区间已经按照「左端点」排过序了,因此当两个区间「合并」的时候,合并后的区间:
a. 左端点就是「前⼀个区间」的左端点;
b. 右端点就是两者「右端点的最⼤值」。
例题五
解法(贪⼼):
贪⼼策略:
a. 按照「左端点」排序;
b. 当两个区间「重叠」的时候,为了能够「在移除某个区间后,保留更多的区间」,我们应该把 「区间范围较⼤」的区间移除。
如何移除区间范围较⼤的区间:由于已经按照「左端点」排序了,因此两个区间重叠的时候,我们应该移除「右端点较⼤」的区间.
例题六
解法(贪⼼):
贪⼼策略:
a. 按照左端点排序,我们发现,排序后有这样⼀个性质:「互相重叠的区间都是连续的」;
b. 这样,我们在射箭的时候,要发挥每⼀⽀箭「最⼤的作⽤」,应该把「互相重叠的区间」统⼀ 引爆。
如何求互相重叠区间?
由于我们是按照「左端点」排序的,因此对于两个区间,我们求的是它们的「交集」:
a. 左端点为两个区间左端点的「最⼤值」(但是左端点不会影响我们的合并结果,所以可以忽略);
b. 右端点为两个区间右端点的「最⼩值」。