LeetCode - 234 - 迴文鏈表 + 9 - 迴文數(爲234題打開思路)

迴文是一個編程中經常出現的概念,大家可能在初期學習C語言時就有判斷迴文的題目出現了8!所以倒着讀和正着讀一模一樣的便是迴文。由此引申出許多概念:迴文數,迴文字符串。這裏又在鏈表上做文章,大家不要怕,微笑着面對這類題。於是在今天講解這道題之前,我們先來回顧一下回文數的判斷,看看有沒有什麼能不能從這道題中有所借鑑。(所以其實第9題只是一道工具題h h h…)

判斷一個整數是否是迴文數。迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。
示例 1:
輸入: 121
輸出: true
示例 2:
輸入: -121
輸出: false
解釋: 從左向右讀, 爲 -121 。 從右向左讀, 爲 121- 。因此它不是一個迴文數。
示例 3:
輸入: 10
輸出: false
解釋: 從右向左讀, 爲 01 。因此它不是一個迴文數。
進階:
你能不將整數轉爲字符串來解決這個問題嗎?

9題原題 https://leetcode-cn.com/problems/palindrome-number/

我解這類題的思路是很清晰的,正着讀和反着讀是一個數,說明轉換爲字符串後,數字從尾巴往頭就應該一模一樣,所以我就用Python的索引判斷,直接1行解決,哪怕是題目示例中的小難題’-'也不會成爲任何問題。這也是我刷LeetCode第一次一行秒殺題目。

class Solution:
    def isPalindrome(self, x: int) -> bool:
    	# 轉換爲字符串後進行[::-1]的逆轉操作並與原先的數字轉換的字符串進行是否相同的判斷
        return str(x)[::-1] == str(x)

那麼我們現在來實現題目進階的目標,不將整數轉化爲字符串:
思路一:我們要實現對迴文的判斷,可以轉換爲實現在在中位點兩側的被分割開的數字是否存在一個reverse的關係的問題。
於是我們將這個數字本身拆解爲兩個數字,一個是逆轉後半部分後的reverseNum,還有一個是後半部分被摘掉以後的x。最後比較這兩個數字是否相等。
明晰了思路以後,怎麼得到這兩個數字就是數學問題了。

在這裏插入圖片描述
附代碼:

class Solution {
public:
    bool isPalindrome(int x) {
    	// 負數與非0整數直接排除
        if ( x < 0 || ( x % 10 == 0 && x != 0 ) ) {
            return false;
        }
		
		// 定義一個reverseNumber記錄逆轉後的後半部分
        int reverseNumber = 0;
        // 當原始數字 / 10 < 反轉後數字 * 10時,此時處理了一半的數字
        while ( x > reverseNumber ) {
        	// 上一輪的reverseNumber * 10 + 每一輪摘出的數
        	// 不難發現新摘出的數都在個位上,reverseNumber因爲乘了10所以之前的位數都往上提了一位 個->十 十->百 百->千...
        	// 與此同時x /= 10
            reverseNumber = reverseNumber * 10 + x % 10;
            x /= 10;
        }
		// 最終比較x前半部分與reverseNumber是否相等
        return x == reverseNumber || x == reverseNumber / 10;
    }
};

思路二:將整個數字按剛纔的思路完全逆轉過來,與原數進行比較。其實有的同學會問:哎,你不怕整數溢出這個問題嘛?我怕,但是我有對策!具體請看代碼!
在這裏插入圖片描述

class Solution {
public:
    bool isPalindrome(int x) {
        if ( x < 0 || ( x % 10 == 0 && x != 0 ) ) {
            return false;
        }
            
        // 用一個變量記錄x,最後是要拿來比較的
        int copy_x = x;
        // 溢出?用一個long變量解決!反正我是懶得寫異常處理了...
        long reverseNumber = 0;
		
		// 	一滴也沒有的時候結束循環
        while ( x > 0 ) {
            reverseNumber = reverseNumber * 10 + x % 10;
            x /= 10;
        }

        return copy_x == reverseNumber;
    }
};

做了那麼多鋪墊,我們現在回到迴文鏈表這道題目中。

請判斷一個鏈表是否爲迴文鏈表。
示例 1:
輸入: 1->2
輸出: false
示例 2:
輸入: 1->2->2->1
輸出: true
進階:
你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題?

234題原題 https://leetcode-cn.com/problems/palindrome-linked-list/

如果真正看懂了上面的兩個思路,這道題就可以秒解了,我們先仿照思路一:找中點並逆轉後半部分,與前半部分做比較。關於找中點的方法可以參考一下我這篇博客(LeetCode - 876 - 鏈表的中間結點),着重講了一下快慢指針的思想,我就不在本題裏細講了。至於逆轉後半部分,之前也在我的博客(LeetCode - 206 - 反轉鏈表)中有詳細的解答。注意,我使用了slow的指針順利找到中點後,逆序的就是slow後面的鏈表結點了!

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if ( !head || !head->next )
            return true;
        
        ListNode *slow = head, *fast = head, *pre = nullptr;
        
        // 快慢指針找到鏈表中點
        while ( fast ) {
            slow = slow->next;
            fast = fast->next ? fast->next->next : fast->next;
        }
        
        // 逆序鏈表後半部分
        while ( slow ) {
            ListNode *temp = slow->next;
            slow->next = pre;
            pre = slow;
            slow = temp;
        }
        
        // head與pre同步往下走,對整個鏈表元素進行遍歷,比較每一個元素,但凡有任意兩個鏈表元素不想等則return false
        while ( head && pre ) {
            if ( head->val != pre->val )
                return false;
            
            head = head->next;
            pre = pre->next;
        }
        
        return true;
    }
};

思路二:反轉整個鏈表後與原鏈表進行比較,這個代碼當作一個作業留給大家吧!因爲寫出這個代碼的前提就是你需要知道如何進行反轉,完成這件事,再像上面一樣進行同步遍歷對元素進行比較就vans了!

博客講解過的Linked-List類的問題的代碼均放在我單獨爲寫鏈表專欄的博客的GitHub裏
https://github.com/18260036169/LeetCode-LinkedList

本次LeetCode刷題就和大家聊到這裏!你的關注就是我莫大的動力!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章