[LeetCode] 906. Super Palindromes 超級回文數



Let's say a positive integer is a *superpalindrome* if it is a palindrome, and it is also the square of a palindrome.

Now, given two positive integers L and R(represented as strings), return the number of superpalindromes in the inclusive range [L, R].

Example 1:

Input: L = "4", R = "1000"
Output: 4
Explanation: 4, 9, 121, and 484 are superpalindromes.
Note that 676 is not a superpalindrome: 26 * 26 = 676, but 26 is not a palindrome.

Note:

  1. 1 <= len(L) <= 18
  2. 1 <= len(R) <= 18
  3. L and R are strings representing integers in the range [1, 10^18).
  4. int(L) <= int(R)

這道題對於正整數定義了一種超級回文數,即其本身是回文數,並且是另一個回文數的平方,現在給了我們一個范圍 [L, R],讓返回這個范圍內所有超級回文數的個數。當然最暴力的辦法就是遍歷每個數字,然后看其是否是回文數字,然后再檢測其平方數是否是回文數,這種方法基本不太可能通過 OJ,因為絕大多的數字都不是回文數,每個都檢測一遍實在是太費時間了,那么應該怎么辦呢?實際上我們應該主動的去構建回文數,對於一個回文數字,若在兩邊各加上一個相同的數字,則新組成的數字一定也是回文數字,那么對於這個新組成的回文數,只需要驗證一下其平方數是否也是回文數即可,這樣就大大的減少了運算步驟,從而逃脫 OJ 的魔爪。

具體來說,由於給定的L和R范圍超過了整型最大值,所以要轉為長整型。然后需要使用上面提到的方法來構建回文數,由於回文數有奇數和偶數兩種形式,比如 22 就是偶數形式,131 就是奇數形式。先構造偶數個的回文數,就是直接在空串的兩端加相同的數字即可,構建的過程放到一個遞歸函數中。同理,構造奇數個的回文數,就是先生成中間的單獨數字,這里可以是從0到9的任意數字,然后再在兩邊加相同的數字,調用遞歸函數。在遞歸函數,首先判斷當前數字的長度,若超過了9,說明當前數字的平方數長度會超過 18,需要直接返回,因為題目中限定了L和R的長度不超過 18。再判斷若當前數字不為空,且第一個數字不為0時,要驗證其平方數是否為回文數。因為多位數的首位不能是0,題目中給定了L和R的范圍是從1開始的,所以不會是單獨的0。此時我們將當前數字的字符串轉為長整型,然后計算其平方數,若該數字大於右邊界 right,則直接返回,否則看若數字大於等於左邊界,且是回文數的話,結果 res 自增1。之后就要繼續構建新的回文數,做法還是在兩邊同時增加兩個相同的數字,並對每個新構建的回文數調用遞歸即可,參見代碼如下:


``` class Solution { public: int superpalindromesInRange(string L, string R) { int res = 0; long left = stol(L), right = stol(R); helper("", left, right, res); for (char c = '0'; c <= '9'; ++c) { helper(string(1, c), left, right, res); } return res; } void helper(string cur, long& left, long& right, int& res) { if (cur.size() > 9) return; if (!cur.empty() && cur[0] != '0') { long num = stol(cur); num *= num; if (num > right) return; if (num >= left && isPalindrome(to_string(num))) ++res; } for (char c = '0'; c <= '9'; ++c) { helper(string(1, c) + cur + string(1, c), left, right, res); } } bool isPalindrome(string str) { int left = 0, right = (int)str.size() - 1; while (left < right) { if (str[left++] != str[right--]) return false; } return true; } }; ```
Github 同步地址:

https://github.com/grandyang/leetcode/issues/906


參考資料:

https://leetcode.com/problems/super-palindromes/

https://leetcode.com/problems/super-palindromes/discuss/170774/Java-building-the-next-palindrome

https://leetcode.com/problems/super-palindromes/discuss/171467/c%2B%2B-straightforward-backtracking-solution

https://leetcode.com/problems/super-palindromes/discuss/170779/Java-Concise-DFS-Solution-with-Explaination-No-Cheating


[LeetCode All in One 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM