234. 回文链表

196 阅读1分钟

[234. 回文链表]

「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」。

题目描述

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

示例

示例1 :

image.png

输入: head = [1,2,2,1]
输出: true

示例 2:

image.png

输入: head = [1,2]
输出: false

提示:

  • 链表中节点数目在范围[1, 105] 内
  • 0 <= Node.val <= 9   进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

思路

在判断回文的时候,在字符串中,一般都是从头和从尾开始一一比较,但是链表不支持从后面开始遍历,所以这个办法不行,但是也可使用额外的空间,将链表转化数组,按上述办法比较。回文有一个性质,就是翻转之后与未翻转时一致,所以我们可以新建一条链表为原链表的翻转,之后进行比较。为了满足进阶的要求,其实我们可以只在原地翻转链表的前半部分,再将前后两部分进行比较即可。找到前半部分可以用速度不同的双指针,翻转链表也是使用双指针,之前的题目已经有过应用。

代码实现

第一个while循环,fast是在辅助找中间的节点。slow节点最后会指向中间节点,并且也在进行翻转的工作。之后在另一个while循环进行比较即可得出结果。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        ListNode* pre = nullptr;
        ListNode* slow = head;
        ListNode* fast = head;
        while(fast!=nullptr && fast->next!=nullptr){   //找中间节点
            fast=fast->next->next;          //二倍速找到中间节点
            ListNode* temp=slow->next;     //翻转slow节点
            slow->next=pre;
            pre=slow;
            slow=temp;
        }
        if(fast!=nullptr) slow=slow->next;      //如果节点数为奇数,那么需要跳过最中间节点,开始比较
        while(slow!=nullptr){                  //比较
            if(slow->val!=pre->val) return false;
            slow=slow->next;
            pre=pre->next;
        }
        return true;
    }
};

总结

在链表上使用双指针,在速度,起点进行了综合考虑。