1. 程式人生 > >[LeetCode] Find the Closest Palindrome 尋找最近的迴文串

[LeetCode] Find the Closest Palindrome 尋找最近的迴文串

Given an integer n, find the closest integer (not including itself), which is a palindrome.

The 'closest' is defined as absolute difference minimized between two integers.

Example 1:

Input: "123"
Output: "121"

Note:

  1. The input n is a positive integer represented by string, whose length will not exceed 18.
  2. If there is a tie, return the smaller one as answer.

這道題給了我們一個數字,讓我們找到其最近的迴文數,而且說明了這個最近的迴文數不能是其本身。比如如果給你個131,那麼就需要返回121。而且返回的迴文數可能位數還不同,比如當n為100的時候,我們就應該返回99,或者給了我們99時,需要返回101。那麼實際上最近迴文數是有範圍的,比如說n為三位數,那麼其最近迴文數的範圍在[99, 1001]之間,這樣我們就可以根據給定數字的位數來確定出兩個邊界值,要和其他生成的迴文數進行比較,取絕對差最小的。

下面我們來看如何求一般情況下的最近迴文數,我們知道迴文數就是左半邊和右半邊互為翻轉,奇數情況下中間還有個單獨的值。那麼如何將一個不是迴文數的數變成迴文數呢,我們有兩種選擇,要麼改變左半邊,要麼改變右半邊。由於我們希望和原數絕對差最小,肯定是改變低位上的數比較好,所以我們改變右半邊,那麼改變的情況又分為兩種,一種是原數本來就是迴文數,這種情況下,我們需要改變中間的那個數字,要麼增加1,要麼減小1,比如121,可以變成111和131。另一種情況是原數不是迴文數,我們只需要改變右半邊就行了,比如123,變成121。那麼其實這三種情況可以總結起來,分別相當於對中間的2進行了-1, +1, +0操作,那麼我們就可以用一個-1到1的for迴圈一起處理了,先取出包括中間數的左半邊,比如123就取出12,1234也取出12,然後就要根據左半邊生成右半邊,為了同時處理奇數和偶數的情況,我們使用一個小tricky,在反轉複製左半邊的時候,我們給rbegin()加上len&1,當奇數時,len&1為1,這樣就不會複製中間數了;為偶數時,len&1為0,這就整個翻轉複製了左半邊。我們把每次生成的迴文串轉為轉為數字後加入到一個集合set中,把之前的兩個邊界值也同樣加進去,最後我們在五個candidates中找出和原數絕對差最小的那個返回,記得別忘了在集合中刪除原數,因為如果原數時迴文的話, i=0時就把自己也加入集合了,參見程式碼如下:

class Solution {
public:
    string nearestPalindromic(string n) {
        long len = n.size(), num = stol(n), res, minDiff = LONG_MAX;
        unordered_set<long> s;
        s.insert(pow(10, len) + 1);
        s.insert(pow(10, len - 1) - 1);
        long prefix = stol(n.substr(0, (len + 1
) / 2)); for (long i = -1; i <= 1; ++i) { string pre = to_string(prefix + i); string str = pre + string(pre.rbegin() + (len & 1), pre.rend()); s.insert(stol(str)); } s.erase(num); for (auto a : s) { long diff = abs(a - num); if (diff < minDiff) { minDiff = diff; res = a; } else if (diff == minDiff) { res = min(res, a); } } return to_string(res); } };

參考資料: