力扣234. 回文链表

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

方法一:使用数组

Ⅰ.遍历链表,将链表的节点依次放入到vector数组中

Ⅱ.这样就将判断链表是否回文的问题,转换成判断数组中的元素是否回文的问题

Ⅲ.利用双指针,left指向第一个元素的下标,right指向最后一个元素的下标,依次判断left、right下标处的元素是否相等,如果不相等返回false

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        //先将链表各个结点的值放入vector数组中
        vector<int> table;
        while(head!=nullptr){
            table.push_back(head->val);
            head=head->next;//移动head的位置,依次让head等于它的下一个元素
        }
        int n=table.size();
        //分别令left、right指向table数组中第一个元素的下标和最后一个元素的下标,
        int left=0;
        int right=n-1;
        //当left<right的时候执行循环体,此处不写为left<=right是因为没有必要相等,因为相等说明left和right指向同一位置,而同一位置的元素必相等。
        while(left<right){
            //如果left和right所指向的元素不相等,返回false
            if(table[left]!=table[right]){
                return false;
            }
            //否则,移动left和right的位置
            ++left;
            --right;
        }
        return true;
    }
};

时间复杂度:O(n),其中 n指的是链表的元素个数。
第一步: 遍历链表并将值复制到数组中,O(n)。
第二步:双指针判断是否为回文,执行了 O(n/2) 次的判断,即 O(n)。
总的时间复杂度:O(2n) = O(n)。
空间复杂度:O(n),其中 n 指的是链表的元素个数,我们使用了一个数组列表存放链表的元素值。


快慢指针

class Solution {
public:
//使用快慢指针的方法,假如结点的个数为奇数:例如1,2,3,2,1的情况,那么slow就移动到第2个2的位置
//如果节点个数为偶数的情况,例如:1,2,2,1,那么slow就移动到第2个2的位置
//此题最终判断的的是以pre为头节点和以slow为头节点的链表是否相等,所以要保证pre和slow长度上相等
//并且为了能够构建出以pre为头结点的链表,要用prepre记住pre的上一个节点
    bool isPalindrome(ListNode* head) {
        //首先判断头节点,以及头节点的下一个节点是否为空,如果二者有一个为空,说明该链表为回文链表
        if(head==nullptr||head->next==nullptr){
            return true;
        }
        //定义需要用到的变量,prepre为空,是因为最后生成的pre链表的结尾一定指向nullptr
        ListNode* slow=head;
        ListNode* fast=head;
        ListNode* pre=head;
        ListNode* prepre=nullptr;
        //如果fast不为空,并且fast的next不为空,才会执行循环体
        //如果不满足条件说明已经可以确定中间节点了
        //例如1,2,3,2,1的情况,循环退出时fast在最后一个1的位置,slow在3的位置
        //例如1,2,2,1的情况,循环退出时fast在nullptr的位置,slow在倒数第2个2的位置
        while(fast!=nullptr&&fast->next!=nullptr){
            pre=slow;              //更新pre位置,为了让pre能接住完成获得半个链表的使命
            slow=slow->next;       //慢指针走一步
            fast=fast->next->next; //快指针走两步
            pre->next=prepre;      //让pre的next指向它的前一个节点
            prepre=pre;            //让它等于当前pre的位置,为了让下次的pre能够找到它的上一个节点
        }
        //这里if语句,是因为链表有奇数节点的情况存在
        //例如1,2,3,2,1的情况,while循环退出时fast在最后一个1的位置,slow在3的位置,为了让pre为头节点的链表可以与slow为节点的链表长度相等,方便判断,所以,奇数结点的时候,要将sloe向后移动一个位置
        if(fast!=nullptr){
            slow=slow->next;
        }
        //例如1,2,3,2,1的情况
        //以pre为头结点的链表为:2->1->nullptr,以slow为头结点的链表为:2->1->nullptr
        //例如1,2,2,1的情况
        //以pre为头结点的链表为:2->1->nullptr,以slow为头结点的链表为:2->1->nullptr
        while(pre!=nullptr&&slow!=nullptr){
            if(pre->val!=slow->val){
                return false;
            }
            pre=pre->next;
            slow=slow->next;
        }
        return true;
    }
};

时间复杂度:O(n),其中 nn 指的是链表的大小。

空间复杂度:O(1)。我们只会修改原本链表中节点的指向,而在堆栈上的堆栈帧不超过 O(1)。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值