算法刷题 | Leetcode 链表典题解题笔记

本文分享了LeetCode上的链表题目解题心得,包括螺旋矩阵的生成、链表元素的删除、设计链表类以及链表相关算法的实现,如反转链表、寻找链表交点和环形链表的检测。强调了循环条件判断、头结点的使用和链表操作技巧。
摘要由CSDN通过智能技术生成

算法刷题 | Leetcode 链表典题解题笔记

摆烂人智商康复刷题第3天
战绩:8题

Leetcode 59. 螺旋矩阵 II

小练一道数组(其实是昨天的尾巴)

代码随想录给出的解法有些麻烦,还要算循环次数,然而只需要加个判断即可代替循环圈数。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> a(n, vector<int>(n)); // 学习初始化
        int cur = 1, tar = n*n;
        int left=0, rig=n-1, top=0, bot=n-1;
        while(cur<=tar){
            if(left==rig && bot==top) a[left][bot]=cur++; // 到最中间一个元素,进入不了下面的循环
            for(int i=left; cur<=tar && i<rig; i++){a[top][i]=cur++;} //上边 从左往右
            for(int i=top; cur<=tar && i<bot; i++){a[i][rig]=cur++;} //右边 从上往下
            for(int i=rig; cur<=tar && i>left; i--){a[bot][i]=cur++;} //底边 从右往左
            for(int i=bot; cur<=tar && i>top; i--){a[i][left]=cur++;} //左边 从下往上
            left++;top++; rig--;bot--;  // 一圈结束,坍缩         
        }
        return a;
    }
};

链表前置知识回顾

结构体指针

  • 定义

    注意点:带指针结构体的定义、构造函数的定义。

    struct ListNode{
    	int val;
    	ListNode *next;
    	ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
    	ListNode(int x, ListNode *next) : val(x), next(next){} // 构造函数2
    }
    
  • 声明

    老忘记格式,做个笔记

    // 法一
    ListNode *p = new ListNode(5); // 初始化赋值为5
    // 法二
    ListNode *q = new ListNode();
    q->val = 5;
    // 法三:先声明一个结构体变量,再将地址赋值给指针
    ListNode nd = new ListNode(5);
    ListNode *p = &nd;
    

链表典题

Leetcode 203. 移除链表元素

  • 法一:啰嗦版

    遍历循环的条件为p->next!=null,不用虚拟节点和pre指针辅助,不过需要在最开始判断头指针是否为空,在最后判断头结点存的数是否为要删除的数。

/**
 * 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* removeElements(ListNode* head, int val) {
        ListNode *p = head, *q;
        if(head==nullptr) return head;
        while(p->next!=nullptr){
            if(p->next->val == val){
                q = p->next;
                p->next = p->next->next;
                delete q; // 释放空间,养成好习惯
            }
            else p = p->next;
        }
        if(head->val==val) head = head->next; // 头结点也存数,最后判断一下
        return head;
    }
};
  • 法二:看起来稍简洁版,挑战用pre指针。

    循环条件为p!=null;

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {        
        ListNode *vhead = new ListNode(0, head);// 添加一个不存数据的头结点
        head = vhead;
        ListNode *p = head->next, *q, *pre=head;       
        while(p!=nullptr){
            if(p->val == val){
                q = p;
                p = p->next;
                pre->next = p;
                delete q;                
            }
            else p = p->next, pre = pre->next;
        }        
        return head->next;
    }
};

Leetcode 707. 设计链表

原始模板

class MyLinkedList {
public:
    
    MyLinkedList() {

    }
    
    int get(int index) {

    }
    
    void addAtHead(int val) {

    }
    
    void addAtTail(int val) {

    }
    
    void addAtIndex(int index, int val) {

    }
    
    void deleteAtIndex(int index) {

    }

};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */
  • 基础补弱:类里面可以定义结构体

    显然,给的模板没有结点定义,我们需要定义结点结构体,看代码随想录发现可以把结构体写进类中,又学到了!同时也发现自己一些基础语法的薄弱,得补补了。

一些测试用例

["MyLinkedList","addAtIndex","addAtIndex","addAtIndex","get"]
[[],[0,10],[0,20],[1,30],[0]]
["MyLinkedList","addAtHead","addAtIndex","get","addAtHead","addAtTail","get","addAtTail","get","addAtHead","get","addAtHead"]
[[],[5],[1,2],[1],[6],[2],[3],[1],[5],[2],[2],[6]]
["MyLinkedList","addAtIndex","addAtIndex","addAtIndex","get"]
[[],[0,10],[0,20],[1,30],[0]]


代码

class MyLinkedList {
public:
    struct Node{
        int val;
        Node *next;
        Node(int x):val(x),next(nullptr){}
        Node(int x, Node *p):val(x),next(p){}
    };
    
    MyLinkedList() {
        head = new Node(0, nullptr);
        length = 0;
    }
    
    int get(int index) {
        if( index<0 || index > (length-1)) return -1;        
        Node *p=head->next;
        while(index--){
            p = p->next;
          }
        return p->val;
    }
    
    void addAtHead(int val) {
        Node *newNode = new Node(val);
        newNode->next = head->next;
        head->next = newNode;
        this->length++;
    }
    
    void addAtTail(int val) {
        Node *p=head;
        while(p->next!=nullptr){ p = p->next;}
        p->next = new Node(val);
        this->length++;
    }
    
    void addAtIndex(int index, int val) {
        if(index>length) return;
                
        Node *p=head; // 带头结点
        while(index--){
            p = p->next;
        }
        Node *newNode = new Node(val);
        newNode->next = p->next;
        p->next = newNode;        
        this->length++;
    }
    
    void deleteAtIndex(int index) {
        if(index<0 || index>=length) return;
        int i=0;            
        Node *p=head->next, *pre = head;
        while(i<index){
            p = p->next;
            pre = pre->next;
            i++;
        }        
        pre->next= p->next;
        delete p;
        length--;
    }
private:
    Node *head;
    int length;
};

Leetcode 206. 反转链表

  • 法一:没什么好说了
/**
 * 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* reverseList(ListNode* head) {
        ListNode *p= new ListNode(0, head), *rtn=nullptr, *q;
        while(p->next!=nullptr){ // 
            q = p->next->next;
            p->next->next = rtn;
            rtn = p->next;
            if(q!=nullptr)p->next = q; 
            else break;
        }
        return rtn;
    }
};
  • 法二:递归(暂时还没练到)

Leetcode 24. 两两交换链表中的节点

掉坑里了,循环条件一开始图方便用 !pre->next && !pre->next->next,压根没进循环。。


class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode *vhead = new ListNode(0, head);
        head = vhead;
        ListNode *p, *q, *pre = head;
        while(pre->next!=nullptr && pre->next->next!=nullptr){ // 都不为空
            p = pre->next;
            q = pre->next->next;            
            pre->next = q;              
            p->next = q->next;
            q->next = p;     
            pre = pre->next->next;            
        }
        return head->next;
    }
};

Leetcode 19. 删除链表的倒数第 N 个结点

快慢指针。

临界情况分析:添加了头结点,p始终在q前面,不会指向同一个元素,p指针先向后挪n次,然后p、q指针一起挪,q挪到最后一个元素位置停止,则p指向元素的下一个是倒数第n个元素,将被删除,让p->next = p->next->next即可,若p恰好指向倒数第n个元素,删除起来跟麻烦些,还需要pre指针。

代码随想录给出的参考q是到Null停止,初始化快慢指针要挪N+1次。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *vhead = new ListNode(0, head);
        head = vhead;
        ListNode *p=head, *q=head;
        while(q->next!=nullptr && n--){
            q = q->next;
        }
        while(q->next!=nullptr){
            p=p->next; q=q->next;
        }
        p->next = p->next->next;
        return head->next;
    }
};

Leetcode面试题 02.07. 链表相交

又一道考研真题。

  • f法一:先上暴力
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *p = headA, *q = headB;
        while(p!=NULL && q!=NULL){
            ListNode *t = q;
            while(t!=NULL){
                if(t == p) return t;
                t = t->next;
            }
            p = p->next;
        }
        return NULL;
    }
};
  • 法二:不会

Leetcode 142. 环形链表 II

链表最后一题!

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *p=head, *q=head;
        while(q!=NULL){
            if(q->next!=NULL)q = q->next->next;
            else break;
            p = p->next;
            if(p == q){// 说明有环, 找环入口
                q = head;
                while(p!=q){
                    p=p->next;
                    q=q->next;
                }
                return q;
            }
        }
        return NULL;
    }
};

总结

  • 循环条件判断p->next是否为空。
  • 没有头结点(不存数据)就创一个,比较方便操作。
  • 链表入环入口寻找:相遇点距离环入口距离等于第一个元素到环入口距离。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值