LeetCode 477 - Largest Palindrome Product


https://leetcode.com/problems/largest-palindrome-product
Find the largest palindrome made from the product of two n-digit numbers.
Since the result could be very large, you should return the largest palindrome mod 1337.
Example:
Input: 2
Output: 987
Explanation: 99 x 91 = 9009, 9009 % 1337 = 987
Note:
The range of n is [1,8].
https://leetcode.com/problems/largest-palindrome-product/discuss/96306/Java-solutions-with-two-different-approaches
There are two directions for approaching the problem: one is to first construct the palindrome and then test whether it can be written as the product of two n-digit numbers; the other is to first obtain the product of the two n-digit number and then test whether the product is a palindrome.

Part I -- From palindrome to product
It looks like most of the posts here took the first approach, so I will start from the first one also. For this approach, we need to consider the following two problems:
  1. How to construct the palindromes and arrange them in descending order (note we are interested in the maximum palindrome).
  2. How to test if a given palindrome can be written as the product of two n-digit numbers.
For the first problem, we need to know how many digits in each of the palindrome. Since the palindrome is meant to be the product of two n-digit numbers, it can have either 2n or 2n - 1 digits. And since we are interested in maximum palindrome, those with 2n digits will be considered first. These palindromes can be divided into two parts with equal number of digits (n for each part): left and right. And left will be a mirror image of right, and vice versa. Therefore each palindrome will be fully determined by either its left or right part.
Note the left part is an n-digit number and if we arrange it in descending order, the resulted palindrome will also be in descending order. Therefore we may start from the maximum n-digit number and go towards the minimum n-digit number. For each number, we can construct the palindrome by concatenating the number with its mirror image.
Now we come to the second problem, i.e., how to check if the constructed palindrome can be written as the product of two n-digit numbers. This is essentially the "integer factorization" problem. One straightforward way would be the "trial division" algorithm, i.e., test each of the n-digit number to see if it is a factor of the palindrome and if so, further check if the other factor is also an n-digit number.
Here is the java problem for this approach. Note we only considered palindromes with 2n digits. Fortunately for each case (n = 1 to 8), we are able to find at least one palindrome that can be decomposed into two n-digit numbers, therefore there is no need to check those with 2n - 1 digits (However if you are still concerned, refer to this post).
public int largestPalindrome(int n) {
    long max = (long)Math.pow(10, n) - 1;
    long min = max / 10;
        
    for (long h = max; h > min; h--) {
        long left = h, right = 0;
        for (long i = h; i != 0; right = right * 10 + i % 10, i /= 10, left *= 10);
        long palindrom = left + right;      // construct the palindrome
            
        for (long i = max; i > min; i--) {
            long j = palindrom / i;
            if (j > i) break;     // terminate if the other number is greater than current number
            if (palindrom % i == 0) return (int)(palindrom % 1337); // found if current number is a factor
        }
    }

    return 9;    // account for case n = 1
}
Apparently the algorithm goes exponentially: O(10^n)
Part II -- Observations and optimizations
Before I continue to the other approach, I'd like to point out some observations and the corresponding optimizations.
As I mentioned, we are interested in the maximum palindrome, thus it's reasonable to first check palindromes starting with digit 9. If not found, then those starting with digit 8, 7, 6,.... If the palindrome is starting with digit 9, it must also be ending with digit 9. Now if the palindrome is the product of the two n-digit numbers, the two numbers must be ending with digits 1, 3, 7, or 9. Similarly for other cases.
It looks like for each n, there exists at least one palindrome with 2n digits and starting with digit 9 that can be written as the product of two n-digit numbers. I was able to prove for the case when n is even, but failed for the case when n is odd.
If n is even, let n = 2k. The two n-digit numbers can be num1 = 10^n - 1 and num2 = 10^n - 10^k + 1. Their product will be p = num1 * num2 = 10^(3k) * (10^k - 1) + (10^k - 1) = 9..0..9, where p will have k leading and trailing digit of 9 and 2k digit 0 in the middle. For n <= 8, this is also the maximum palindrome that is found (not sure if it holds true for higher n, but most likely it will do).
If n is odd, the above trick does not work (p will have unbalanced 9's). For this case, however, I would like to propose the following statement: let n = 2k + 1, there exists at least two n-digit numbers num1 and num210^n - 10^(k+1) <= num1, num2 <= 10^n - 1, whose product will be a palindrome (verified for n <= 8).
In summary, we have the following conclusion: for each n, there exists at least two n-digit numbers num1 and num210^n - 10^m <= num1, num2 <= 10^n - 1 and m = [(n+1)/2], whose product will be a palindrome.
http://bookshadow.com/weblog/2017/01/05/leetcode-largest-palindrome-product/
解法I 构造回文+校验除数
输入范围n∈[1, 8],除n = 1以外,其余n值最大回文数palindrome的位数均为偶数,可以拆分为half与reversed(half)左右两半

从上界high = pow(10, n) - 1向下界low = pow(10, n - 1)枚举half,构造回文,检查是否存在两个n位数的除数
public int largestPalindrome(int n) { if (n == 1) { return 9; } int high = (int) Math.pow(10, n) - 1, low = high / 10; for (int i = high; i > low; i--) { long palindrome = createPalindrome(i); for (long j = high; j > low; j--) { if (palindrome / j > high) { break; } if (palindrome % j == 0) { return (int) (palindrome % 1337); } } } return -1; } private long createPalindrome(long num) { String str = num + new StringBuilder(Long.toString(num)).reverse().toString(); return Long.parseLong(str); }
http://blog.csdn.net/sheldon0227/article/details/64922216


http://www.tonyliu.info/2017/03/16/Algorithms-479
  1. Search all the palindrome in [10^(2n - 1), 10^(2n)]. (from big to small)
    e.g.
     for (int i = 10 ^ n - 1; i >= 10 ^ (n - 1); i--) { 
         pal = i append inverse(i);
         ...
     }
    
  2. Check if the number is a product of two n-digit number. e.g.
    // Givn i, check if i is a product of two n-digit number:
    for (int j = 10 ^ (n - 1); j <= sqrt(i); j++) {
        if (pal % j == 0 && len(pal/j) == n)
         // then i is the answer.
    }
    
  3. Build a palindrome from a number:
     // convert num to string.
     // invert the string using reverse().
     // append the new string to the old string.
     // convert string to num.
     // return num.
    
  4. Complexity: O(10^n) * O(10^(n/2) = O(10^((3/2)n))
    So when n == 8, we have 10^12 times of check, which is large, but fortunately the answer is near to the upper bound so in practice it’s very fast.

    int largestPalindrome(int n) {
        if (1 == n) return 9; // Since there is only 1 digit in the palindrome, we can't generate it using below method.
        // Search from max possible value of num1 to the min possible value of num1.
        int upper = pow(10, n) - 1, lower = pow(10, n - 1);
        for (int i = upper; i >= lower; i--) {
            long cand = buildPalindrome(i);
            for (int j = upper; j >= cand / j; j--) {
                if (0 == cand % j && to_string(cand / j).size() == n) {
                    return cand % 1337;
                }
            }
        }
        return -1;
    }
    // turn "abc" to "cba"
    long buildPalindrome(int n) {
        string str = to_string(n);
        reverse(str.begin(), str.end());
        return stol(to_string(n) + str);
    }

    // Run all the possible input and record them. O(1)
    int answer(int n) {
        int ans[10] = {0, 9, 987, 123, 597, 677, 1218, 877, 475};
        return ans[n];
    }
https://discuss.leetcode.com/topic/74372/an-easy-9-line-java-solution
    public int largestPalindrome(int n) {
        if (n==1) return 9;
        int max=(int)Math.pow(10, n)-1;
        for (int v=max-1;v>max/10;v--) {
            long u=Long.valueOf(v+new StringBuilder().append(v).reverse().toString());
            for (long x=max;x*x>=u;x--)
                if (u%x==0)
                    return (int)(u%1337);
        }
        return 0;
    }
X.
Part III -- From product to palindrome
Similar to the first approach, we need to consider the following two problems:
  1. How to construct the products and arrange them in descending order.
  2. How to test if a given product is a palindrome.
The second problem is easy, simply reverse the product and check if it is the same as the original product. The first problem, however, is a little tricky. Obtaining the product is a no-brainer. The hard part is how to arrange them in descending order.
First we need to determine the candidate products. From part II, we will only consider products obtained with the two n-digit numbers in the range [10^n - 10^m, 10^n - 1]. Second we will use a PriorityQueue to extract these candidate products in descending order.
However, the total number of candidates above still blows up the memory when n = 8. So we need further pruning. First again since the product ends with digit 9, the two numbers must be ending with digits 1, 3, 7, or 9. Second, to avoid repetition, the first number will be no less than the second. Third, for all products obtained with the first number fixed, there is no need to include them all at once but instead we can consider them once at a time with the second number going in decreasing order. So eventually we end up storing the two numbers in the PriorityQueue while extracting them according to their product.
With these optimizations, here is the java program for this approach:
public int largestPalindrome(int n) {
    int max = (int)Math.pow(10, n) - 1;
    int min = max - (int)Math.pow(10, (n + 1) >> 1);
     
    Comparator<int[]> cmp = new Comparator<int[]>() {
     @Override
 public int compare(int[] a, int[] b) {
         return Long.compare((long)b[0] * b[1], (long)a[0] * a[1]);
     }
    };
     
    PriorityQueue<int[]> pq = new PriorityQueue<>(max - min, cmp);
     
    for (int i = max; i > min; i--) {
     int r = i % 10;
      
     if (r == 3 || r == 7) {
         pq.offer(new int[] {i, i});
     } else if (r == 1) {
         pq.offer(new int[] {i, i - 2});
     } else if (r == 9) {
         pq.offer(new int[] {i, i - 8});
     }
    }
     
    while (!pq.isEmpty()) {
     int[] a = pq.poll();
     long p = (long)a[0] * a[1];
      
     if (isPalindrome(p)) return (int)(p % 1337);
      
     if (a[1] > min) {
         a[1] -= 10;
         pq.offer(a);
     }
    }
    
    return 0;
}
    
private boolean isPalindrome(long z) {
    long r = 0;
    for (long x = z; x != 0; r = r * 10 + x % 10, x /= 10);
    return r == z;
}
This algorithm still goes exponentially with n while also requires extra space of the same order

X. https://blog.csdn.net/magicbean2/article/details/78683871
1、查表法:既然题目中说了n的范围是[1, 8],那么我们提前计算出8个结果存放在表中,在函数中直接返回即可。还有谁比我更流氓?
    int largestPalindrome(int n) {
        long long ret[8] = {9, 9009, 906609, 99000099, 9966006699, 999000000999, 99956644665999, 9999000000009999};
        return ret[n - 1] % 1337;

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