LeetCode 788 - Rotated Digits


https://leetcode.com/problems/rotated-digits/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.  Each digit must be rotated - we cannot choose to leave it alone.
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 and become invalid.
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].
X. O(logn)
http://www.frankmadrid.com/ALudicFallacy/2018/02/28/rotated-digits-leet-code-788/
The critical intuition is: we want numbers that contain only 0182569, but also at least one 2569. If you still remember how we handled this at least one situation during school, you should realize you just have to subtract the count of only-contain-0182569 by the count of only-contain-018 (which means, does not contain 2569) numbers.
From left to right. At the first digit, we first exclude N[0], then we count the number of only-0182569 numbers in c, then the only-018 numbers, which is stored in e.
The only thing left is what is that exclude for? It's actually for you to deal with N[0] which we have not handled yet. As you can see the picture above, when we now move on, with i++, we actually are handling numbers that start with N[0] rather than 0 itself. 0 led numbers are actually handled in the previous iteration of i==0 because both c and e contains 0.
At i==1, we implicitly have N[0] at the first digit of our to-be-assembled number. Now, we sure should include it in our new c at this iteration, only to choose the trailing parts properly. What about e? For example, if N[0] is 6, then we should not include anything in the new e, because anything like 6+[only_contain_018] does not belong to the only-contain-018 category anymore.

The idea is very nice, but using pow at each iteration will possibly make your time complexity O((lgN)^2) (unless you know to argue with the interviewer that java's pow is O(1) or O(lgN) depending on you). Instead, you can iterate on the pow result:
class Solution {
    private int[] allPossibleCount = new int[]  {1,    2,    3,    3,    3,    4,    5,    5,    6,   7};       // 0,1,2,5,6,8,9
    private int[] excludeNumCount = new int[]   {1,    2,    2,    2,    2,    2,    2,    2,    3,   3};       // 0, 1, 8
    private boolean[] isValid = new boolean[]   {true, true, true, false,false,true, true, false,true,true};    // 0,1,2,5,6,8,9
    private boolean[] isExclude = new boolean[] {true, true, false,false,false,false,false,false,true,false};   // 0,1,8
    
    public int rotatedDigits(int N) {
        char[] cs = Integer.toString(N).toCharArray();
        int len = cs.length, count = 0;
        boolean exclude = true;
        int base7 = (int) Math.pow (7, len - 1), base3 = (int) Math.pow (3, len - 1);
        for (int i = 0; i < len; i++, base7 /= 7, base3 /= 3) {
            if (cs[i] == '0' && i != len - 1) continue;
            int index = i == len - 1 ? cs[i] - '0' : cs[i] - '0' - 1;
            double c = allPossibleCount[index] * base7;
            double e = exclude ? excludeNumCount[index] * base3 : 0; // # of numbers which only contain 0,1,8
            count += c - e;
            if (!isValid[cs[i] - '0']) break;
            exclude = exclude & isExclude[cs[i] - '0'];
        }
        return count;
    }

https://leetcode.com/problems/rotated-digits/discuss/116530/O(logN)-Solution
  • += 7 ** means you could pick digits from this set [0, 1, 8, 2, 5, 6, 9], there are 7 different kinds of digits in this set, right?
  • -= 3 ** is similar to the above, except that this time the set is [0, 1, 8]
Here is solution in O(logN) complexity.
def rotatedDigits(self, N):
        s1 = set([0, 1, 8])
        s2 = set([0, 1, 8, 2, 5, 6, 9])
        s = set()
        res = 0
        N = map(int, str(N))
        for i, v in enumerate(N):
            for j in range(v):
                if s.issubset(s2) and j in s2:
                    res += 7**(len(N) - i - 1)
                if s.issubset(s1) and j in s1:
                    res -= 3**(len(N) - i - 1)
            if v not in s2:
                return res
            s.add(v)
        return res + (s.issubset(s2) and not s.issubset(s1))

X. Digit DP
http://www.cnblogs.com/grandyang/p/9154892.html
其实这道题还有更好的解法呢,使用动态规划Dynamic Programming来做的,思路非常巧妙,博主深为叹服。定义了一个长度为N+1的一维布尔型DP数组,其中dp[i]表示数字i的三种状态,0表示数字i翻转后不合法,1表示数字i翻转后和原数相同,2表示数字i翻转后形成一个不同的数字。那么根据题目中的定义可知,只有当dp[i]=2的时候才是好数字。那么下面来看状态转移方程吧,我们知道如果数字只有1位的话,那么判断起来很简单,如果是0,1,和8中的一个,那么dp[i]=1,如果是2,5,6,和9中的一个,那么dp[i]=2,并且结果res自增1。如果是剩下的三个数字3,4,7中的一个不用更新,因为dp数组初始化就为0。下面来看数字i大于10的情况,非常的经典,dp[i] 的值其实可以从 dp[i/10] 和 dp[i%10] 这两个状态值转移而来,由于我们更新的顺序是从小到大,所以当要更新dp[i]的时候,dp[i/10] 和 dp[i%10] 这两个状态值已经算过了。为啥dp[i] 的值是由这两个状态值决定的呢?因为每个数字都是相互独立的翻转,比如四位数字abcd,可以拆分为三位数abc,和个位数d,如果abc翻转后仍是abc,d翻转后仍是d,说明abcd翻转后仍是abcd,所以dp[i]=1,只要其中有一个大于1了,另外一个至少是1的话,那么说明可以翻转成不同的数字,dp[i]=2,并且结果res自增1

https://leetcode.com/problems/rotated-digits/discuss/117975/Java-dp-solution-9ms
Using a int[] for dp.
dp[i] = 0, invalid number
dp[i] = 1, valid and same number
dp[i] = 2, valid and different number
    public int rotatedDigits(int N) {
        int[] dp = new int[N + 1];
        int count = 0;
        for(int i = 0; i <= N; i++){
            if(i < 10){
                if(i == 0 || i == 1 || i == 8) dp[i] = 1;
                else if(i == 2 || i == 5 || i == 6 || i == 9){
                    dp[i] = 2;
                    count++;
                }
            } else {
                int a = dp[i / 10], b = dp[i % 10];
                if(a == 1 && b == 1) dp[i] = 1;
                else if(a >= 1 && b >= 1){
                    dp[i] = 2;
                    count++;
                }
            }
        }
        return count;
    }

https://leetcode.com/problems/rotated-digits/discuss/116547/Easily-Understood-Java-Solution
    public int rotatedDigits(int N) {
        int count = 0;
        for (int i = 1; i <= N; i ++) {
            if (isValid(i)) count ++;
        }
        return count;
    }
    
    public boolean isValid(int N) {
        /*
         Valid if N contains ATLEAST ONE 2, 5, 6, 9
         AND NO 3, 4 or 7s
         */
        boolean validFound = false;
        while (N > 0) {
            if (N % 10 == 2) validFound = true;
            if (N % 10 == 5) validFound = true;
            if (N % 10 == 6) validFound = true;
            if (N % 10 == 9) validFound = true;
            if (N % 10 == 3) return false;
            if (N % 10 == 4) return false;
            if (N % 10 == 7) return false;
            N = N / 10;
        }
        return validFound;
    }

Improved efficiency. Increments i if the leading digit of i is 3, 4 or 7.
For example, if i = 300, then we know 300, 301, 302 ... 399 are all invalid. IncrementIfNeeded(int i) returns 99 to set i to 399 and 400 after i++ from loop increment.
The same thing happens for 400.
Therefore, we only check 300 and 400, rather than 300, 301, 302, ..., 399, 400, 401, 402, ..., 499.
    public int rotatedDigits(int N) {
        int count = 0;
        for (int i = 1; i <= N; i ++) {
            if (isValid(i)) count ++;
            i += incrementIfNeeded(i);
        }
        return count;
    }
    
    public int incrementIfNeeded(int i) {
        int inc = 1;
        while (i >= 10) {
            inc *= 10;
            i /= 10;
        }
        if (i == 3 || i == 4 || i == 7) return inc - 1;
        else return 0;
    }
    
    public boolean isValid(int N) {
        /*
         Valid if N contains ATLEAST ONE 2, 5, 6, 9
         AND NO 3, 4 or 7s
         */
        boolean validFound = false;
        while (N > 0) {
            if (N % 10 == 2) validFound = true;
            if (N % 10 == 5) validFound = true;
            if (N % 10 == 6) validFound = true;
            if (N % 10 == 9) validFound = true;
            if (N % 10 == 3) return false;
            if (N % 10 == 4) return false;
            if (N % 10 == 7) return false;
            N = N / 10;
        }
        return validFound;
    }

    def rotatedDigits(self, N):
        """
        :type N: int
        :rtype: int
        """
        dmap = {"0" : "0", "1" : "1", "8" : "8", "2" : "5", "5" : "2", "6" : "9", "9" : "6"}
        res = 0
        for num in range(1, N + 1):
            if any(x in str(num) for x in ["3", "4", "7"]):
                continue
            if any(x in str(num) for x in ["2", "5", "6", "9"]):
                res += 1
        return res

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts