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刷题就和大家聊到这里!你的关注就是我莫大的动力!

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