贪心算法 坏了的计算器

2020-06-18 15:20 更新

题目

难度:简单

在显示着数字的坏计算器上,我们可以执行以下两种操作:

双倍(Double):将显示屏上的数字乘 2; 递减(Decrement):将显示屏上的数字减 1 。

最初,计算器显示数字 X。

返回显示数字 Y 所需的最小操作数。

示例 1:

  1. 输入:X = 2, Y = 3
  2. 输出:2
  3. 解释:先进行双倍运算,然后再进行递减运算 {2 -> 4 -> 3}.

示例 2:

  1. 输入:X = 5, Y = 8
  2. 输出:2
  3. 解释:先递减,再双倍 {5 -> 4 -> 8}.

示例 3:

  1. 输入:X = 3, Y = 10
  2. 输出:3
  3. 解释:先双倍,然后递减,再双倍 {3 -> 6 -> 5 -> 10}.

示例 4:

  1. 输入:X = 1024, Y = 1
  2. 输出:1023
  3. 解释:执行递减运算 1023

提示:

1 <= X <= 10^9 1 <= Y <= 10^9

题解一

为什么这道题采用逆向思维更优?

1.刚开始的时候觉得很简单,用了两个while,结果报错了。因为可以先减去再去乘以就会节省次数

正向思维:在X/Y时要实现操作数最小,要将X逼近Y的1/2值或1/4值或1/8值或...再进行*2操作,难点在于要判断要逼近的是1/2值还是1/4值还是其他值,逻辑复杂 逆向思维:在Y>X时Y只管/2,到了Y\<X时在+1逼近 说白了就是,正向思维采用的是先小跨度的-1操作,再大跨度的*2操作;逆向思维采用的是先大跨度的/2操作,再小跨度的-1操作 然而事实上往往是先大后小的解决问题思维在实现起来会比较简单 cur=y;存储yn=0;次数

2.什么时候可以先减去再去乘以?Y是一个偶数 3.所以先把cur+1成为偶数 4.再/2处理,小于X之后跳出循环 5.这时候n+x-cur即为结果x-cur为x与cur之间还需要进行的几次操作

  1. class Solution {
  2. public int brokenCalc(int X, int Y) {
  3. int cur=Y,n=0;
  4. while(X<cur){
  5. n++;
  6. if(cur%2==1){
  7. cur++;
  8. }
  9. else{
  10. cur/=2;
  11. }
  12. }
  13. return n+X-cur;
  14. }
  15. }

解法二:递归

  1. class Solution {
  2. public int brokenCalc(int X, int Y) {
  3. if (X >= Y) {
  4. return X - Y;
  5. }
  6. if (Y % 2 == 1) {
  7. return 2 + brokenCalc(X, (Y + 1) / 2);
  8. } else {
  9. return 1 + brokenCalc(X, Y / 2);
  10. }
  11. }
  12. }

解法三:分步

只需要讨论 Y > X时的情况。分为两步统计, cnt1为多少个乘法,cnt2为多少个减法。 显然我们必须把 X 乘到恰好比 Y 大的数,否则再怎么减也达不到要求……因此先求 cnt1. 那么,关键是 cnt2 怎么求呢?我们假设减法穿插在各个乘法之间,如果在第一次乘法前减,那么最终等价于减去 2cnt12^{cnt1}2cnt1, 如果在第二次乘法前减,最终等价于减去 2cnt1−12^{cnt1 - 1}2cnt1−1,以此类推。由于每次可以减多个1,因此最终要乘个系数,减了 a 2cnt12^{cnt1}2cnt1 + b 2cnt1−12^{cnt1 - 1}2cnt1−1 + .... 那么这个系数 a,b,c等等是多少呢,贪心即可,a越大越好,其次到b, c...

  1. class Solution {
  2. public int brokenCalc(int X, int Y) {
  3. if (Y <= X) return X - Y;
  4. int cnt1 = 0;
  5. while (X < Y) {
  6. X *= 2;
  7. cnt1 ++;
  8. }
  9. if (X == Y) return cnt1;
  10. int r = X - Y;
  11. int cnt2 = 0;
  12. for (int i = cnt1; i >= 0; i --) {
  13. int t = (int)Math.pow(2, i);
  14. int coeff = r / t;
  15. r = r % t;
  16. cnt2 += coeff;
  17. if (r == 0) break;
  18. }
  19. return cnt1 + cnt2;
  20. }
  21. }
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号