Leetcode 刷题笔记-Leetcode 101 第13章 链表

Leetcode 刷题笔记-Leetcode 101 第13章 链表

链表

(单)链表是由节点和指针构成的数据结构,每个节点存有一个值,和一个指向下一个节点的指针,因此很多链表问题可以用递归来处理。不同于数组,链表并不能直接获取任意节点的值,必须要通过指针找到该节点后才能获取其值。同理,在未遍历到链表结尾时,我们也无法知道链表的长度,除非依赖其他数据结构储存长度。

链表的基本操作

Leetcode 206

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* p = nullptr;
        ListNode* q = head;
        while(q){
            ListNode* r = q->next;
            q->next = p;
            p = q;
            q = r;
        }
        return p;
    }
};

分析:两种方式,迭代法和递归法反转链表。

错误:算法忘记了,稍稍看了一眼后明白了

Leetcode 21

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode* result = new ListNode(-1);
        ListNode* head = result;
        while(list1 != nullptr && list2 != nullptr){
            if(list1->val > list2->val){              
                head->next = list2;
                list2 = list2->next;
            }
            else{
                head->next = list1;
                list1 = list1->next;
            }
            head = head->next;
        }
        if(list1 != nullptr){
            head->next = list1;
        }
        else{
            head->next = list2;
        }
        return result->next;
    }
};

分析:按照顺序一点一点合并即可,前面设置一个头结点,后面把它扔掉返回。

错误:链表操作忘记了

Leetcode 24

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* pre = new ListNode(-1);
        pre->next = head;
        head = pre;
        while(pre->next != nullptr && pre->next->next != nullptr){
            ListNode* p = pre->next;
            ListNode* q = p->next;
            pre->next = q;
            p->next = q->next;
            q->next = p;
            pre = p;
        }
        return head->next;
    }
};

分析:链表操作

错误:已经不熟练了,不知道什么时候加结点什么的。

其它链表技巧

Leetcode 160

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA == nullptr || headB == nullptr){
            return nullptr;
        }
        ListNode* pa = headA;
        ListNode* pb = headB;
        while(pa != pb){
            if(pa == nullptr){
                pa = headB;
                pb = pb->next;
            }
            else if(pb == nullptr){
                pb = headA;
                pa = pa->next;
            }
            else{
                pa = pa->next;
                pb = pb->next;
            }
        }
        return pa;
    }
};

分析:当链表headA和headB都不为空时,创建两个指针pA和pB,初始时分别指向两个链表的头节点headA和headB,然后将两个指针依次遍历两个链表的每个节点。具体做法如下:每步操作需要同时更新指针pA和pB。如果指针pA不为空,则将指针pA移到下一个节点;如果指针 pB不为空,则将指针pB移到下一个节点。如果指针pA为空,则将指针pA移到链表headB的头节点;如果指针pB为空,则将指针pB移到链表headA的头节点。当指针pA和pB指向同一个节点或者都为空时,返回它们指向的节点或者null。

错误:不会做

Leetcode 234

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

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        vector<int> vt;
        while(head != nullptr){
            vt.push_back(head->val);
            head = head->next;
        }
        int n = vt.size();
        for(int i=0;i<n/2;++i){
            if(vt[i] != vt[n-i-1]){
                return false;
            }
        }
        return true;
    }
};

分析:复制到数组中判断

一遍AC

练习

Leetcode 83

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode* p = head;
        if(p == nullptr){
            return nullptr;
        }
        while(p->next != nullptr){
            ListNode* q = p->next;
            if(p->val == q->val){
                p->next = q->next;
                q = p->next;
            }
            else{
                q = q->next;
                p = p->next;
            }
        }
        return head;
    }
};

分析:遍历判断即可

错误:没有考虑链表中没有结点的情况。

Leetcode 328

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        if(head == nullptr){
            return head;
        }
        ListNode* odd = head;
        ListNode* even = head->next;
        ListNode* evenhead = even;
        while(even != nullptr && even->next != nullptr){
            odd->next = even->next;
            even->next = even->next->next;
            odd = odd->next;
            even = even->next;
        }
        odd->next = evenhead;
        return head;
    }
};

分析:单独存储奇偶结点即可。

错误:还是不熟练

Leetcode 19

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* p = head;
        int sum = 0;
        while(p != nullptr){
            ++sum;
            p = p->next;
        }
        p = head;
        int num = sum - n;
        if(num == 0){
            return head->next;
        }
        ListNode* pre = new ListNode(-1);
        pre->next = p;
        for(int i=0;i<num;++i){
            pre = p;
            p = p->next;
        }
        pre->next = p->next;
        return head;
    }
};

分析:先数一遍一共有多少个结点,然后再遍历一遍删掉即可。

一遍AC

Leetcode 148

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head == nullptr){
            return head;
        }
        vector<int> result;
        ListNode* p = head;
        while(head != nullptr){
            result.push_back(head->val);
            head = head->next;
        }
        sort(result.begin(),result.end());
        head = p;
        int index = 0;
        while(head != nullptr){
            head->val = result[index++];
            head = head->next;
        }
        return p;
    }
};

分析:可以用一些比较高大上的链表排序方法,也可以耍赖,直接读入数组中排序即可。

一遍AC

总结

链表不难,就是太容易忘记了,后面要经常复习。


Leetcode 刷题笔记-Leetcode 101 第13章 链表
https://zhangzhao219.github.io/2022/09/14/Leetcode/Leetcode-101/Leetcode-101-13/
作者
Zhang Zhao
发布于
2022年9月14日
许可协议