代码随想录算法训练营第三天|203 移除链表元素、707设计链表、206反转链表

链表

  1. 在内存中不连续
  2. 插入和删除的复杂度为O(1),查询的复杂度为0(n),和数组刚好相反
  3. 链表可扩展,数组不可扩展
  4. 有单链表、双链表、循环链表等

链表的定以结构如下:

struct ListNode{
	int val;
	ListNode *next;
	ListNode(int x):val(x), next(nullptr){}

203 移除链表元素

题目链接:移除链表元素

思路

移除链表元素看起来是很简单的,但是写起来比较难以思考。首先有一点:删除头结点和中间的节点是不一样的(因为头结点没有前一个元素)。所以要对头结点和其他节点单独处理。第二点:删除元素时不能让cur指在要删除的元素上,要指在它的上一个元素,因为你要让cur->next = cur->next->next,如果指在了要删除的元素上,则无法找到它的上一个元素。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //
        while(head != nullptr && head->val == val){
            ListNode *delNode = head;
            head = head->next;
            delete delNode;
        }
        ListNode *cur = head;
        while(cur!=nullptr && cur->next != nullptr){
            if(cur->next->val == val){
                ListNode *delNode = cur->next;
                cur->next = cur->next->next;
                delete delNode;
            }
            else{
                cur = cur->next;
            }
        }
        return head;
 }

};

使用虚拟头结点的方法则可以将头节点和其余节点一起进行处理,不用再区分是不是头结点,是一个很好的方法。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyNode = new ListNode();
        dummyNode->next = head;
        ListNode* cur = dummyNode;
        while(cur->next!=nullptr){
            if(cur->next->val == val){
                ListNode* delNode = cur->next;
                cur->next = cur->next->next;
                delete delNode;
            }
            else{
                cur = cur->next;
            }
        }
        return dummyNode->next;
 }
};

707 设计链表

题目链接:设计链表

思路

设计链表,首先要定义链表的节点,然后一个链表应该有一个头指针(作为哨兵,也就是虚拟头指针,并不计入链表的元素数量,也就是这个指针并不是链表中的元素)和记录链表中元素多少的变量sizesize是链表中元素的个数,而不是下标的最大值。
之前我总想着的是把这个哨兵指针当成链表中的元素,导致代码出错。

class MyLinkedList {
public:
    struct ListNode
    {
        int val;
        ListNode* next;
        ListNode(int x):val(x),next(nullptr){}
    };
    
    MyLinkedList() {
        dummpyHead = new ListNode(0);
        size = 0;
    }
    
    int get(int index) {
        if(index >= size){
            return -1;
        }
        ListNode *cur = dummpyHead->next;
        while(index--){
            cur=cur->next;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        ListNode *insertNode = new ListNode(val);
        insertNode->next = dummpyHead->next;
        dummpyHead->next = insertNode;
        size++;
    }
    
    void addAtTail(int val) {
        ListNode *insertNode = new ListNode(val);
        ListNode *cur = dummpyHead;
        while(cur->next != nullptr){
            cur = cur->next;
        }
        cur->next = insertNode;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        if(index>size){
            return;
        }
        ListNode *insertNode = new ListNode(val);
        ListNode *cur = dummpyHead;
        while(index--){
            cur = cur->next;
        }
        insertNode->next = cur->next;
        cur->next = insertNode;
        size++;
    }
    
    void deleteAtIndex(int index) {
        if(index >= size){
            return;
        }
        ListNode *cur = dummpyHead;
        while(index--){
            cur = cur->next;
        }
        cur->next = cur->next->next;
        size--;
    }
private:
    ListNode* dummpyHead;
    int size;
};

206 翻转链表(五颗星)

题目链接:翻转链表

思路

乍一看,,因为数组的思想已经根深蒂固,想着把链表中的元素给翻转过来。然后。。。。。。就没有然后了。感觉自己的思维很混乱。
看了题解以及视频,才明白使用双指针法两个两个的改变链表中next的朝向。没有想到这一点,但是想到了要改变next的朝向,使用双指针两两改变。太厉害了,真的是太厉害了。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *cur = head;
        ListNode *pre = nullptr;
        while(cur != nullptr){
            ListNode *tmp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
};

参考链接

  1. https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E6%80%9D%E8%B7%AF

你可能感兴趣的:(C++,算法,链表,数据结构)