代码随想录刷题笔记2——链表

移除链表元素

例题203(简单)移除链表元素

注意要点:

  1. 链表题目涉及增减元素,可以设置虚拟头节点,辅助把链表的所有元素的逻辑操作同化;
  2. 删除元素,相当于next变成next->next。

下面贴出代码:

CPP版本

/**
 * 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* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* cur = dummy;
        while (cur->next)
        {
            if (cur->next->val == val)
            {
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            }
            else {cur = cur->next;}
        }
        head = dummy->next;
        delete dummy;
        return head;
    }
};

C版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeElements(struct ListNode* head, int val){
    if (!head) {return head;}
    struct ListNode* dummyhead = malloc(sizeof(struct ListNode));
    dummyhead->next = head;
    struct ListNode* tail = dummyhead;
    while (tail->next)
    {
        if (tail->next->val == val)
        {
            struct ListNode* temp = tail->next;
            tail->next = tail->next->next;
            free(temp);
        }
        else {tail = tail->next;}
    }
    return dummyhead->next;
}

设计链表

例题707(中等)设计链表

注意要点:

  1. 类中创建时,可以设置private变量:虚拟头结点以及当前链表长度辅助计算
  2. 增添和删减元素时,涉及index都需要和链表长度先行比较;
  3. get的操作需要从头结点开始,也就是虚拟头结点的next节点;其余操作均从虚拟头结点开始

下面贴出代码:

CPP版本

class MyLinkedList {
public:
    struct LinkedNode
    {
        int val;
        LinkedNode* next;
        LinkedNode(int val): val(val), next(nullptr){}
    };

    MyLinkedList() {
        dummy = new LinkedNode(0);
        size = 0;
    }
    
    int get(int index) {
        if (index >= size || index < 0) {return -1;}
        LinkedNode* cur = dummy->next;
        while (index--) {cur = cur->next;}
        return cur->val;
    }
    
    void addAtHead(int val) {
        LinkedNode* newhead = new LinkedNode(0);
        newhead->val = val;
        LinkedNode* tmp = dummy->next;
        dummy->next = newhead;
        newhead->next = tmp;
        size++;
    }
    
    void addAtTail(int val) {
        LinkedNode* cur = dummy;
        while (cur->next) {cur = cur->next;}
        LinkedNode* newtail = new LinkedNode(0);
        cur->next = newtail;
        newtail->val = val;
        newtail->next = nullptr;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        if (index > size) {return;}
        if (index < 0) {index = 0;}
        LinkedNode* cur = dummy;
        while (index--) {cur = cur->next;}
        LinkedNode* newnode = new LinkedNode(val);
        newnode->next = cur->next;
        cur->next = newnode;
        size++;
    }
    
    void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {return;}
        LinkedNode* cur = dummy;
        while (index--) {cur = cur->next;}
        LinkedNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete(tmp);
        tmp = nullptr;
        size--;
    }
private:
    LinkedNode* dummy;
    int size;
};

/**
 * 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);
 */

C版本

struct ListNode* ListNodeCreate(int val)
{
    struct ListNode* node = (struct ListNode* )malloc(sizeof(struct ListNode));
    node->val = val;
    node->next = NULL;
    return node;
}

typedef struct {
    struct ListNode* head;
    int size;
} MyLinkedList;


MyLinkedList* myLinkedListCreate() {
    MyLinkedList* obj = (MyLinkedList* )malloc(sizeof(MyLinkedList));
    obj->head = ListNodeCreate(0);
    obj->size = 0;
    return obj;
}

int myLinkedListGet(MyLinkedList* obj, int index) {
    if (index < 0 || index >= obj->size) {return -1;}
    struct ListNode* cur = obj->head->next;
    while (index--) {cur = cur->next;}
    return cur->val;
}

void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    struct ListNode* head = obj->head;
    struct ListNode* newhead = ListNodeCreate(val);
    newhead->next = head->next;
    head->next = newhead;
    obj->size++;
}

void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    struct ListNode* cur = obj->head;
    while (cur->next) {cur = cur->next;}
    struct ListNode* newtail = (struct ListNode* )malloc(sizeof(struct ListNode));
    newtail->val = val;
    cur->next = newtail;
    newtail->next = NULL;
    obj->size++;
}

void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    if (index > obj->size) {return;}
    index = fmax(0, index);
    struct ListNode* cur = obj->head;
    while (index--) {cur = cur->next;}
    struct ListNode* newnode = ListNodeCreate(val);
    newnode->next = cur->next;
    cur->next = newnode;
    obj->size++;
}

void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    if (index < 0 || index >= obj->size) {return;}
    struct ListNode* cur = obj->head;
    while (index--) {cur = cur->next;}
    struct ListNode* tmp = cur->next;
    cur->next = cur->next->next;
    free(tmp);
    obj->size--;
}

void myLinkedListFree(MyLinkedList* obj) {
    struct ListNode* cur = obj->head;
    struct ListNode* tmp = NULL;
    while (cur)
    {
        tmp = cur;
        cur = cur->next;
        free(tmp);
    }
    free(obj);
}

/**
 1. Your MyLinkedList struct will be instantiated and called as such:
 2. MyLinkedList* obj = myLinkedListCreate();
 3. int param_1 = myLinkedListGet(obj, index);
 
 4. myLinkedListAddAtHead(obj, val);
 
 5. myLinkedListAddAtTail(obj, val);
 
 6. myLinkedListAddAtIndex(obj, index, val);
 
 7. myLinkedListDeleteAtIndex(obj, index);
 
 8. myLinkedListFree(obj);
*/

翻转链表

例题206(简单)翻转链表

注意要点:

  1. 本题可以不用虚拟头结点,养成加上的习惯避免不时之需;
  2. 翻转的思路是找到当前节点的前一个节点,并修改当前节点的next指针,然后向后移动一位;所以需要保存pre以及cur->next辅助计算

下面贴出代码:

CPP版本

/**
 * 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* cur = head;
        ListNode* pre = nullptr;
        while (cur)
        {
            ListNode* tmp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
};

C版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* dummy = (struct ListNode* )malloc(sizeof(struct ListNode));
    dummy->next = head;
    struct ListNode* cur = dummy->next;
    struct ListNode* pre = NULL;
    while (cur)
    {
        struct ListNode* tmp = cur->next;
        cur->next = pre;
        pre = cur;
        cur = tmp;
    }
    return pre;
}

两两交换链表中的节点

例题24(中等)两两交换链表中的节点

注意要点:

  1. 设置虚拟头结点,避免头结点的不同处理;
  2. 交换一共涉及四个节点,分别为待交换的两个节点,以及前一和后一节点;所以需要两个tmp来记录帮助交换(一个也可以,但都是next很容易搞晕)。

下面贴出代码:

CPP版本

/**
 * 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* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* cur = dummy;
        while (cur->next && cur->next->next)
        {
            ListNode* tmp1 = cur->next;
            ListNode* tmp2 = cur->next->next->next;
            cur->next = tmp1->next;
            tmp1->next->next = tmp1;
            tmp1->next = tmp2;
            cur = tmp1;
        }
        return dummy->next;
    }
};

C版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* swapPairs(struct ListNode* head){
    struct ListNode* dummyhead = (struct ListNode* )malloc(sizeof(struct ListNode));
    dummyhead->next = head;
    struct ListNode* cur = dummyhead;
    while (cur->next && cur->next->next)
    {
        struct ListNode* tmp = cur->next;
        struct ListNode* tmp1 = cur->next->next->next;
        cur->next = cur->next->next;
        cur->next->next = tmp;
        cur->next->next->next = tmp1;
        cur = cur->next->next;
    }
    return dummyhead->next;
}

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

例题19(中等)删除链表的倒数第N个节点

注意要点:

  1. 避免删除的是头结点,所以设置虚拟头节点辅助计算;
  2. 通过快慢指针,快指针移动(n+1)次,再与慢指针一起移动直至链表尾部,慢指针所在位置即为倒数(n+1)所在
  3. 移动n+1次,就可以直接通过next来删除倒数第n个,避免还要记录pre节点。

下面贴出代码:

CPP版本

/**
 * 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* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* slow = dummy;
        ListNode* fast = dummy;
        while (n--) {fast = fast->next;}
        fast = fast->next;
        while (fast)
        {
            slow = slow->next;
            fast = fast->next;
        }
        ListNode* tmp = slow->next;
        slow->next = slow->next->next;
        delete(tmp);
        tmp = nullptr;
        return dummy->next;
    }
};

C版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    struct ListNode* dummyhead = malloc(sizeof(struct ListNode));
    dummyhead->next = head;
    struct ListNode* slow = dummyhead;
    struct ListNode* fast = dummyhead;
    while (n--) {fast = fast->next;}
    fast = fast->next;
    while (fast)
    {
        slow = slow->next;
        fast = fast->next;
    }
    slow->next = slow->next->next;
    return dummyhead->next;
}

链表相交

例题160(简单)链表相交

注意要点:

  1. 通过遍历长度,并使得两链表的当前指针对齐,进而可以同时移动指针判断是否相交
  2. 对齐方法:计算链表长度差,并在长链表指针移动长度差个次数,来对齐两个指针;
  3. 相交是地址相等,不能简单判断值相等。

下面贴出代码:

CPP版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int totalA = 0, totalB = 0;
        ListNode* curA = headA;
        ListNode* curB = headB;
        //统计两个链表的长度
        while (curA) {curA = curA->next; totalA++;}
        while (curB) {curB = curB->next; totalB++;}

        //移动到距离结尾相同距离处
        curA = headA, curB = headB;
        int sub = totalA - totalB;
        if (sub > 0)
        {
            while (sub--) {curA = curA->next;}
        }
        else {while (sub++) {curB = curB->next;}}

        //判断地址是否相同,而不是val是否相同
        while (curA)
        {
            if (curA == curB) {return curA;}
            else
            {
                curA = curA->next;
                curB = curB->next;
            }
        }
        return NULL;
    }
};

C版本

/**
 1. Definition for singly-linked list.
 2. struct ListNode {
 3.     int val;
 4.     struct ListNode *next;
 5. };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode* p1 = malloc(sizeof(struct ListNode));
    struct ListNode* p2 = malloc(sizeof(struct ListNode));
    p1->next = headA;
    p2->next = headB;
    int l1 = 0, l2 = 0;
    while (p1->next)
    {
        p1 = p1->next;
        l1++;
    }
    while (p2->next)
    {
        p2 = p2->next;
        l2++;
    }
    p1 = headA;
    p2 = headB;
    int delta = l1 - l2;
    // printf("delta = %d\n", delta);
    // printf("p1 = %d\n", p1);
    if (delta >= 0)
    {
        while(delta--) {p1 = p1->next;}
    }
    else
    {
        while(delta++) {p2 = p2->next;}
    }
    // printf("p1 = %d\n", p1);
    while (p1)
    {
        if (p1 == p2)
        {
            return p1;
        }
        p1 = p1->next;
        p2 = p2->next;
    }
    return NULL;
}

环形链表

例题142(中等)环形链表II

注意要点:

  1. 是否成环的判断:快慢指针,快指针走两步,慢指针走一步,如果能相遇,则证明成环;记录下当前节点;
  2. 寻找成环点快指针从当前节点出发,慢指针从头结点出发,移动相同步数,相遇点即为成环点。

这道题涉及到的数学推导可以自行退导一下,不乐意推导就直接记结论就可以做题了。

下面贴出代码:

CPP版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* slow = head;
        ListNode* fast = head;
        while (fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast)  //有环
            {
                //从相遇节点,slow回到head,再次移动同样步数,再次相遇就是成环点
                slow = head;
                while (slow != fast)
                {
                    slow = slow->next;
                    fast = fast->next;
                }
                return slow;
            }
        }
        return NULL;
    }
};

C版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast)
        {
            while (slow != head)
            {
                slow = slow->next;
                head = head->next;
            }
            return head;
        }
    }
    return NULL;
}

总结

再次白嫖代码随想录,这个总结的思维导图真的好!!!!
链表知识点总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值