LeeCode_234. 回文链表(暴力+栈+快慢指针+递归)

 一、介绍

1.题目描述

题目链接:https://leetcode-cn.com/problems/palindrome-linked-list/

请判断一个链表是否为回文链表。

进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题

  • 链表是单向的

2.测试样例

[1,2]  # false

[1,2,2,1]  # true

二、题解

1、暴力🟢

(1)新建数组,遍历链表并将每个节点的值存储到数组中,转换为回文数组的问题。

(2)双指针从数组头尾向中间靠拢,如果出现不一样的值,则不是回文链表

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        // temp记录数值,num统计节点个数
        vector<int> temp;
        int num=0;
        // 遍历到末尾后结束循环
        while(head!=nullptr){
            // 存储值
            temp.push_back(head->val);
            num++;
            head=head->next;
        }
        // 头尾指针指向的数值不一致,不是回文
        for(int i=0;i<num/2;i++){
            if(temp[i]!=temp[num-i-1]) return false;
        }
        return true;
    }
};

 2、栈🟢

(1)遍历一次链表,得到链表长度 n。

(2)指针从头向后移,依次将n/2个元素推入栈

(3)此时指针在后半截起始的位置,依次弹出栈元素并和当前指向的元素值对比,不同则不是回文

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        int n=0;
        ListNode *p=head;
        // 统计链表长度
        while(p!=nullptr){
            n++;
            p=p->next;
        }
        if(n==1) return true;
        stack<int> stk;
        p=head;
        int k=(n+1)/2;  // 一半的位置
        // 向栈中推入前半截元素,结束后指针在后半截起始处
        for(int i=0;i<k;i++){
            stk.push(p->val);
            p=p->next;
        }
        // 弹出栈元素,和后半截依次对比
        // 如果链表长度为奇数,要弹出居中的数再开始比较
        if(n%2!=0) stk.pop();
        while(p!=nullptr){
            if(stk.top()!=p->val) return false;
            stk.pop();
            p=p->next;
        }
        return true;
    }
};

 3、快慢指针🟡

思路:设置快慢指针,快指针 q 一次移动2格,慢指针 p 1格,慢指针移动的同时对链表反转。当快指针到头,慢指针在中间位置。此时从中间和开头分别遍历,比较数值是否相同

  • 如果链表长度为奇数,居中的数反转后在开头,但不参与比较,从开头的下一个节点开始比较
  • 利用flag标志长度奇偶。快指针在第一次移动发现已经是末尾,说明是偶数。在第二次移动发现是末尾,说明是奇数

参考链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/hui-wen-lian-biao-by-leetcode-solution/637525

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if(head->next==nullptr) return true;
        ListNode *p=head,*q=head,*pre=nullptr;
        int flag=0;
        while(q->next!=nullptr){
            q=q->next;
            if(q->next!=nullptr){
                // q 后移
                q=q->next;
                // p指向的后一个节点插入到链表开头【即对前半截反转】
                pre=p->next;
                p->next=p->next->next;
                pre->next=head;
                head=pre;
            }
            // 如果尾指针第二次后移发现已经到头,说明是奇数
            else flag=1;
        }
        // 尾指针指向链表后半截起始处
        q=p->next;
        // 如果是奇数,从头节点下一个开始比较
        p=flag==0?head->next:head;
        // 不同则不是回文
        while(q!=nullptr){
            if(q->val!=p->val) return false;
            q=q->next;
            p=p->next;
        }
        return true;
    }
};

4、 递归🔴

① pre 为头指针,head为尾指针。

② 通过递归,head不断后移,指向末尾,比较末尾与初始位的数值是否相同

  • 若不同,逐层返回 false,结果为 false
  • 若相同,pre后移,向上一层返回 true,比较上一层【即倒数第二个节点和整数第二个节点】值是否相同

③ 重复步骤2直至递归结束

参考链接:https://leetcode-cn.com/problems/palindrome-linked-list/solution/hui-wen-lian-biao-by-leetcode-solution/

class Solution {
ListNode *pre;
public:
    bool isPalindrome(ListNode* head) {
        pre=head;
        return huiwen(head);
    }

    bool huiwen(ListNode* head){
        if(head!=nullptr){
            if(huiwen(head->next)==false) return false;
            if(head->val!=pre->val) return false;
            pre=pre->next;
        }
        return true;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值