代码随想录额外题目| 链表 ●234回文链表●143重排链表 ●141环形链表

#234回文链表 

简单方法很简单(转成vector判断),难的方法有点难, 很巧妙 

简单方法:

 bool isPalindrome(ListNode* head) {
        vector<int> vec;
        ListNode* cur=head;
        while(cur){
            vec.push_back(cur->val);
            cur=cur->next;
        }
        int start=0; int end=vec.size()-1;
        while(start<=end){
            if(vec[start]!=vec[end]) return false;
            start++; end--;
        }
        return true;
        
    }

难的方法: 

学习随想录+一些自己的实现。要点:

1.找到LL中间点:

while (fast && fast->next) {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }

pre->next = nullptr;  

一定要用slow前面那个,然后前半段比后半段是奇数的话少一个,要使用slow整个就不对了。不知道怎么想出来的,但是测试一下是这样的

2.随想录的翻转和我写的略微有不同:其实不用管cur->next是不是null。但现在是第二遍做翻转LL写出来了,算是会了吧。

ListNode* reverseList(ListNode* head) {
        ListNode* temp; // 保存cur的下一个节点
        ListNode* cur = head;
        ListNode* pre = nullptr;
        while(cur) {
            temp = cur->next;  // 保存一下 cur的下一个节点,因为接下来要改变cur->next
            cur->next = pre; // 翻转操作
            // 更新pre 和 cur指针
            pre = cur;
            cur = temp;
        }
        return pre;
    }

整体代码: 

bool isPalindrome(ListNode* head) {
        if (head->next == nullptr) return true;
        ListNode* slow = head; // 慢指针,找到链表中间分位置,作为分割
        ListNode* fast = head;
        ListNode* pre = head; // 记录慢指针的前一个节点,用来分割链表
        while (fast && fast->next) {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        pre->next = nullptr; 

        ListNode* cur1 = head;  // 前半部分
        ListNode* cur2 = reverseList(slow); 
        

        while (cur1) {//equal of cur1 longer
            if (cur1->val != cur2->val) return false;
            cur1 = cur1->next;
            cur2 = cur2->next;
        }
        return true;
    }

    ListNode* reverseList(ListNode* head){
        ListNode* cur=head;
        ListNode* pre=nullptr;
        ListNode* tmp=nullptr;
        while(cur && cur->next){
            tmp=cur->next;
            cur->next=pre;
            pre=cur;
            cur=tmp;
            
        }
        cur->next=pre;
        return cur;
    }

#143重排链表

用纯粹的链表法就会和#234回文LL很像,我想的&&我写的:

void reorderList(ListNode* head) {
        if(!head->next) return;
        ListNode* slow=head;
        ListNode* fast=head;
        ListNode* pre=head;
        while(fast && fast->next){
            pre=slow;
            slow=slow->next;
            fast=fast->next->next;
        }
        pre->next=nullptr;
        //slow is the head2, LL1 shorter
        
        ListNode* cur1=head;
        ListNode* cur2=reverse(slow);
        ListNode* tmp;
        ListNode* tmp2;
        while(cur1 && cur1->next){
            tmp=cur1->next;
            tmp2=cur2->next;
            cur1->next=cur2;
            cur2->next=tmp;

            cur1=tmp;
            cur2=tmp2;
        }
        cur1->next=cur2;
        
    }

    ListNode* reverse(ListNode* head){
        ListNode* pre=nullptr;
        ListNode* cur=head;
        ListNode* tmp=nullptr;

        while(cur){
            tmp=cur->next;
            cur->next=pre;
            pre=cur;
            cur=tmp;
        }
        return pre;
    }

思路和随想录一样的:

 但是随想录主函数实现和我略有不同:

void reorderList(ListNode* head) {
        if (head == nullptr) return;
        // 使用快慢指针法,将链表分成长度均等的两个链表head1和head2
        // 如果总链表长度为奇数,则head1相对head2多一个节点
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast && fast->next && fast->next->next) {
            fast = fast->next->next;
            slow = slow->next;
        }
        ListNode* head1 = head;
        ListNode* head2;
        head2 = slow->next;
        slow->next = nullptr;

        // 对head2进行翻转
        head2 = reverseList(head2);

        // 将head1和head2交替生成新的链表head
        ListNode* cur1 = head1;
        ListNode* cur2 = head2;
        ListNode* cur = head;
        cur1 = cur1->next;
        int count = 0; // 偶数取head2的元素,奇数取head1的元素
        while (cur1 && cur2) {
            if (count % 2 == 0) {
                cur->next = cur2;
                cur2 = cur2->next;
            } else {
                cur->next = cur1;
                cur1 = cur1->next;
            }
            count++;
            cur = cur->next;
        }
        if (cur2 != nullptr) { // 处理结尾
            cur->next = cur2;
        }
        if (cur1 != nullptr) {
            cur->next = cur1;
        }
    }

 其他方法:1. LL放到vec然后一前一后双指针 2.把链表放进双向队列,然后通过双向队列一前一后弹出数据,来构造新的链表 (从来没写过双向队列,真是神奇的东西)

void reorderList(ListNode* head) {
        deque<ListNode*> que;
        ListNode* cur = head;
        if (cur == nullptr) return;

        while(cur->next != nullptr) {
            que.push_back(cur->next);
            cur = cur->next;
        }

        cur = head;
        int count = 0; // 计数,偶数去后面,奇数取前面
        ListNode* node;
        while(que.size()) {
            if (count % 2 == 0) {
                node = que.back();
                que.pop_back();
            } else {
                node = que.front();
                que.pop_front();
            }
            count++;
            cur->next = node;
            cur = cur->next;
        }
        cur->next = nullptr; // 注意结尾
    }

#141环形链表

constraints真的很重要,看了一眼蛮小的:number of the nodes in the list is  [0, 10^4]

就想了个神奇方法,用个数判断

    bool hasCycle(ListNode *head) {
        ListNode *cur=head;
        int cnt=0;
        while(cur){
            cnt++;
            if(cnt>10000) return true;
            cur=cur->next;
        }
        return false;
    }

又写了个用set装的:时间和空间表现都不好 

bool hasCycle(ListNode *head) {
        set<ListNode *> myset;
        ListNode* cur=head;
        while(cur){
            if(myset.find(cur)==myset.end()) myset.insert(cur);
            else return true;
            cur=cur->next;
        }

        return false;
    }

随想录方法:快慢指针相遇判断成环(好重要的方法) ,142.环形链表II 这道重要的题就是这样做的,还要用数学计算,我居然忘了

bool hasCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
            
            if (slow == fast) return true;
        }
        return false;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值