LeetCode-788. Rotated Digits

本文探讨了一个数字旋转问题,即在180度旋转后得到不同的有效数字。文章提供了两种算法解决方案,包括暴力枚举(Brute Force)和动态规划算法,并详细解释了这两种方法的工作原理及实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

X is a good number if after rotating each digit individually by 180 degrees, we get a valid number 
that is different from X. A number is valid if each digit remains a digit after rotation. 0, 1, and 
8 rotate to themselves; 2 and 5 rotate to each other; 6 and 9 rotate to each other, and the rest of 
the numbers do not rotate to any other number.

Now given a positive number N, how many numbers X from 1 to N are good?

Example

Input: 10
Output: 4
Explanation: 
There are four good numbers in the range [1, 10] : 2, 5, 6, 9.
Note that 1 and 10 are not good numbers, since they remain unchanged after rotating.

Note

N  will be in range [1, 10000].

Solution 1(C++)

#define SAME 0 // 0, 1, 8
#define VALID 1 // 2, 6, 8, 9
#define INVALID 2 // 3, 4, 7

class Solution {
public:
    int rotatedDigits(int n) {
        int i, num, count = 0, is_valid[] = {SAME, SAME, VALID, INVALID, INVALID, VALID, VALID, INVALID, SAME, VALID};
        bool found = false;
        for(i = 2; i <= n; i++){
            num = i; found = false;
            while(num){
                if(is_valid[num % 10] == INVALID) {found = false; break;}
                if(is_valid[num % 10] == VALID) found = true; 
                num = num/10;
            }
            if(found == true) count++;
        }
        return count;
    }
};

Solution 2(C++)

class Solution {
public:
  // Digits:                    0 1 2 3 4 5 6 7 8 9
  int type[10]               = {0,0,1,2,2,1,1,2,0,1};  // 'Same' 'New' or 'Invalid' numbers
  int differentRotations[10] = {0,0,1,1,1,2,3,3,3,4};  // Cumulative: New number
  int validRotations[10]     = {1,2,3,3,3,4,5,5,6,7};  // Cumulative: Valid number
  int sameRotations[10]      = {1,2,2,2,2,2,2,2,3,3};  // Cumulative: Same number

  int countRotations(std::string str, bool isNewNumber) {

      int digit = str[0] - '0'; 
      if(str.length() == 1) return isNewNumber ? validRotations[digit] : differentRotations[digit];

      int ret = 0;
      if(digit != 0) {

          ret += validRotations[digit-1] * std::pow(7,str.length() - 1);

          if(!isNewNumber) ret -= sameRotations[digit-1] * std::pow(3, str.length() - 1);
      }

      if(type[digit] == 1) isNewNumber = true;

      if(type[digit] != 2) ret += countRotations(str.substr(1, std::string::npos), isNewNumber);

      return ret;
  }

  int rotatedDigits(int N) { return countRotations(std::to_string(N), false); }
};

算法分析

这道题,有两种主要的解法,一种是暴力枚举,也就是Brute Force算法。另一种就比较复杂了,是动态规划算法。解法二的答案参考了一篇博客:A Ludic Fallacy - Rotating Digits (Leet Code 788)。别人这博客写的挺好的。

emmm,别人的博客说的其实挺详细的,如果我翻译一遍的话,一方面是太麻烦了,很多数学符号,另一方面,也没啥技术含量。所以,我在这里就做一点解释。

这个方法重点在于要看懂博客中的两个决策树(Decision Tree)。红色方块的就是旋转后的数字不是数字的,所以不用考虑。黄色与绿色的都是旋转后还是数字的,但是黄色的是旋转之后和原来的数字一样的,比如:0、1、8。 绿色的是旋转后与原来的数字不一样的,可以参考LED显示的数字:2、5、6、9。那么,如果一个数字按照题目的要求,每一位上的数字分别旋转180度,如果含有红色方框的数字就不用考虑了。只有含有黄色与绿色的数字才可以,这样算起来,就是”有效的数字“——valid number。但有效的数字不一定是”好的数字“——”good number”。因为题目要求好的数字是,旋转之后与原来的数字不一样。所以要想不一样,必须含有一个绿色方框的数字,也就是说,之前计算的有重复。重复的部分就是全部是黄色框的数字,这部分的数字不含有绿色数字,比如:1、18、118、108等等。所以,在结合组成的新的数字不能超过N。就可以算出答案了。

多一句嘴,我倒是没看出这里哪里和我理解的动态规划有关系的。有可能解法二中的四个数组的生成考虑到了“动态规划”的思想吧。但不得不说,这道题还不错。值得日后反复做一做。

程序分析

emmm。程序值得说的地方太多了。还是自己动手写一写最好。要说性价比最高的当然就是解法一了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值