LeetCode397.整数替换---记忆化递归、贪心题解

397. 整数替换

给定一个正整数 n ,你可以做如下操作:

如果 n 是偶数,则用 n / 2替换 n 。
如果 n 是奇数,则可以用 n + 1或n - 1替换 n 。
n 变为 1 所需的最小替换次数是多少?

示例 1:

输入:n = 8
输出:3
解释:8 -> 4 -> 2 -> 1

  • 1 <= n <= 2^31 - 1

解法1

看到题目给出 n 有两种状态,分别对应不同操作时,首先想到动态规划。但是再看一眼数据范围,无法创建动态规划数组,会爆内存。

退一步想,dp 递推大部分由递归总结而来,本题用递归做的话,不需要开一个很大的数组,只需要 HashMap 缓存一下结果就行。

确定解法:记忆化递归

class Solution {

    HashMap<Long,Integer> map = new HashMap<>();

    public int integerReplacement(int n) {
        if(n == 1) return 0;
        dfs(n);
        return map.get((long)n);
    }

    public int dfs(long n){
        if(n == 1) return 0;
        if(map.containsKey(n)) return map.get(n);
        int res = 0;
        if(n % 2 == 0){
            res = dfs(n / 2) + 1;
        }else{
            int v1 = dfs(n - 1);
            int v2 = dfs(n + 1);
            res = Math.min(v1,v2) + 1;
        }
        int cnt = map.getOrDefault(n,0x3f3f3f3f);
        map.put(n,Math.min(cnt,res));
        return res;
    }
}

解法2 贪心

贪心的思想自己没想出来,看了大佬的题解才有了一点思路,写篇博客记录一下。–思路不对请大佬纠正。

最终目的是将 n 转换为 1(000…0001)。

当 n 是偶数时,只有一种操作 --> /2。也就是局部最优的。

当 n 是奇数时,分为两种操作,根据操作方式的不同,影响结果。所以当 n 是奇数时,要分情况讨论,选出局部最优的选择。

当 n 是奇数时,如果 +1 / -1 能使后续奇数情况更少,那么对结果的影响更小,答案更优。那么目标就是找到一个"分界点",能够对 +1,-1分情况讨论。

我们可以发现,n 为奇数时,% 4分为两种情况,余数为1,余数为3。

int s = n % 4;
if(s == 1){
	n --> n + 1(偶数) --> (n + 1) / 2(奇数) -->...
	n --> n - 1(偶数) --> (n - 1) / 2(偶数) -->...
	发现当余数为1时,进行 n-1 操作,后续奇数情况更少
	n--;
}else{
	n --> n + 1(偶数) --> (n + 1) / 2(偶数) -->...
	n --> n - 1(偶数) --> (n - 1) / 2(奇数) -->...
	发现当余数为1时,进行 n-1 操作,后续奇数情况更少
	n++;
}

对总结出的情况进行反证法:

当余数为 1 时,如果进行 +1 操作得到偶数,偶数再 /2 得到结果为奇数:(n + 1) / 2。对 (n + 1) / 2 分情况讨论:

-1 操作得到偶数 (n - 1) / 2。偶数 /2 得到 (n - 1) / 4。共四步。

+1 操作得到偶数 (n + 3) / 2。偶数 /2 得到 (n + 3) / 4。共四步。

当余数为 1 时,进行 -1 操作。得到 (n - 1) / 4。需要 -1 – /2 – /2 三步。得到 (n + 3) / 4 。需要 -1 – /2 – /2 – +1 四步。

总结当余数为 1 时,-1 操作局部更优。

当余数为 3 时,同理,得到 +1 操作局部更优。

但是考虑特例情况,当 n = 3 时。+1 操作 --> 3 – 4 – 2 – 1 四步。 -1 操作 --> 3 – 2 – 1 三步。

总结贪心代码:

class Solution {
    //找到特殊点,然后分情况讨论结果。
    //偶数只有一种方式,/2,
    //只有奇数判断怎么走,才会影响最终结果
    //所以越少奇数越好
    public int integerReplacement(int n1) {
        int res = 0;
        long n = n1;
        while(n != 1){
            if(n % 2 == 0){
                // n /= 2;
                n >>= 1;
            }else{
                long s = n % 4;
                if(n == 3){
                    n--;
                    res++;
                    continue;
                }
                if(s == 1){
                    //n -- n + 1(偶数) -- (n+1)/2 奇数
                    //n -- n - 1(偶数) -- (n-1)/2 偶数
                    n--;
                }else{
                    //n -- n + 1(偶数) -- (n+1)/2 偶数
                    //n -- n - 1(偶数) -- (n-1)/2 奇数
                    n++;
                }
            }
            res ++;
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值