LeetCode破解之得到目标值的最少行动次数

238 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

题目说明

你正在玩一个整数游戏。从整数 1 开始,期望得到整数 target 。

在一次行动中,你可以做下述两种操作之一:

递增,将当前整数的值加 1(即, x = x + 1)。 加倍,使当前整数的值翻倍(即,x = 2 * x)。 在整个游戏过程中,你可以使用 递增 操作 任意 次数。但是只能使用 加倍 操作 至多 maxDoubles 次。

给你两个整数 target 和 maxDoubles ,返回从 1 开始得到 target 需要的最少行动次数。

示例 1:

输入:target = 5, maxDoubles = 0 输出:4 解释:一直递增 1 直到得到 target 。

贪心

核心思想:使用贪心算法倒序处理,加倍变成减半,递增变成递减 先消耗掉所有减半次数 maxDoubles,消耗过程中如果是偶数则减半,如果是奇数则递减,每次消耗次数 count 都加1 剩余的操作只能是递减,需要的操作次数为剩余整数减1即 target - 1 最后返回 count + target - 1。

具体步骤:

1. 从target反推回1;
2. 若target是奇数,那么就只能进行减1操作;
3. 若target是偶数,那么就进行除2操作,同时maxDoubles;
4. 当maxDoubles次数用完或者target已经为1时退出循环,若此时target还不为1,那么就只能做减1操作直到target为1。
class Solution {
    public int minMoves(int target, int maxDoubles) {
        int count = 0;
        while (target>1){
            int b = target%2;
            if (b!=0){
                count++;
                target--;
            }
            if (maxDoubles>0){
                maxDoubles--;
                count++;
                target/=2;
            }
            else{
                count+=(target-1);
                target=1;
            }
        }
        return count;
    }
}

递归

思路:根据是否可以被2整除分情况讨论,判断递归出口。三种情况如下

  • 如果 target == 1,则返回 0,代表不用进行操作
  • 如果 maxDoubles == 0,则返回 target - 1,因为不能乘只能加,所以返回 target 和 1 的差
  • 如果 maxDoubles > 0,代表还有乘二次数,如果 target 为偶数,就直接除,否则减 1 再除
class Solution {
    public int minMoves(int target, int maxDoubles) {
        
        if(target == 1 || maxDoubles == 0){
            return target - 1;
        }
     
        if(target % 2 == 0 && maxDoubles >= 0 && target >= 1)
        
            return minMoves(target / 2, maxDoubles - 1) + 1;
        else
          
            return minMoves((target - 1) / 2, maxDoubles - 1) + 2;
    }
}

注意

当target为奇数时,说明前一步只能是递增行动,因此通过递归的方式退回1步,即总最小步数=1+minMoves(target-1, maxDoubles);

如果当target为偶数时,前一步操作是加倍时,步数最小,即总最小步数=1+minMoves(int(target/2), maxDoubles-1)