训练营第四天

两两交换链表中的节点

链表貌似就是虚头+双指针+遍历,回到老家的感觉,注意对空节点的检查就好,题不难

/**
 * 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:
    ListNode* swapPairs(ListNode* head) {
        ListNode * virhead = new ListNode();
        if(head == nullptr || head->next == nullptr) return head;
        virhead->next = head;
        ListNode * left = virhead;
        ListNode * right = head;
        while(right && right->next) {
            left->next = right->next;
            right->next = right->next->next;
            left->next->next = right;
            left = right;
            right = right->next;
        }
        return virhead->next;
    }
};

删除链表的倒数第n个节点

算脑筋急转弯吧,不过之前做过,已经没有难度了,思路就是让fast先走n步,再和slow一起走,这样fast走到最后slow就是倒数第n个了。

评论区diss官解的“一次遍历”说法,去搜了一下,看见了宫水三叶前辈的帖,下为结论:

出处:为什么「一次遍历」要比「两次遍历」慢 (含小实验代码) | Java 刷题打卡-阿里云开发者社区 (aliyun.com)

/**
 * 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:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode * vir = new ListNode();
        vir->next = head;
        ListNode * fast = vir;
        ListNode * slow = vir;
        for(int i = 0;i < n;i++) {
            fast = fast->next;
        }
        while(fast && fast->next) {
            slow = slow->next;
            fast = fast->next;
        }
        ListNode * t = slow->next;
        slow->next = slow->next->next;
        delete t;
        return vir->next;
    }
};

链表相交

思路比较原始,都走一遍,把屁股对齐,长的先走几步把优势消耗,然后一起走找交点。

官解的追及思路更优雅,不过复杂度相同。官解

/**
 * 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:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode * vir = new ListNode();
        vir->next = head;
        ListNode * fast = vir;
        ListNode * slow = vir;
        for(int i = 0;i < n;i++) {
            fast = fast->next;
        }
        while(fast && fast->next) {
            slow = slow->next;
            fast = fast->next;
        }
        ListNode * t = slow->next;
        slow->next = slow->next->next;
        delete t;
        return vir->next;
    }
};

环形链表II

数学题,刚开始没推出来,注意把环分成走过的b段和没走过的c段,这样就很直观了,贴个图帮助理解

公式中a对应图中x,y对应b,z对应c

求的是a,slow被碰到时离入口还差c,所以此时再来个指针从头开始一起走,碰到的时候刚好就是等式两边,即入口。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode * fast = head;
        ListNode * slow = head;
        while(fast) {
            slow = slow->next;
            if(!fast->next) return nullptr;
            fast = fast->next->next;
            if(fast == slow) {
                ListNode * ans = head;
                while(ans != slow) {
                    ans = ans->next;
                    slow = slow->next;
                }
                return ans;
            }
        }
        return nullptr;
    }
};

不太难,链表问题不大,注意空指针检查就行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值