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 <= len(L) <= 18
1 <= len(R) <= 18
L
andR
are strings representing integers in the range[1, 10^18)
.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
[LeetCode All in One 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)