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

@代码随想录算法训练营第3天 | Leetcode203 移除链表元素, 707 设计链表,206 反转链表

203 移除链表元素

视频链接:
https://www.bilibili.com/video/BV1fA4y1o715/?share_source=copy_web&vd_source=ea38fc37ab446e2a02645366e71adf5d

第一遍读题思考(五分钟内,如果没有思路就写暴力解法思路,暴力解法思路也不清晰就写无)

对链表操作不太熟悉,所以直接看解析。

代码随想录解法思路

所谓删除链表就是把当前节点的next重新指向next的next,然后delete掉next的node,不过需要注意头节点和非头节点处理的不同之处如果头节点删除,那么需要把头节点的下一个节点换成头节点,但是非头节点的删除只需要把next换成next的next就好,两者的操作是不一样的。为了统一操作,引入dummyhead作为头节点,链接在原始的头节点之前,然后只需要按照正常操作即可。

c++代码具体实现注意事项

没啥需要注意的,就是记得delete不要的节点。

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

学习时长

707 设计链表

第一遍读题思考(五分钟内,如果没有思路就写暴力解法思路,暴力解法思路也不清晰就写无)

应该还是用虚拟头节点的方法,主要的难点在与判断指针遍历到哪个位置了。

代码随想录解法思路

差不多的思路,还是要关注链表指针遍历到哪里。需要注意插入的时候cur->next应该先赋值给newNode不然就断了。

c++代码具体实现注意事项

这个代码涉及到class的构建,需要在类里构建一个单节点struct,然后定义其中的私有变量,比如链表的尺寸用于后续的操作。详细的看一下下面的代码。

class MyLinkedList {

public:
    struct LinkNode{
        int val;
        LinkNode* next;
        LinkNode(int val): val(val), next(nullptr){}
    };
    MyLinkedList() {
        _dummyhead = new LinkNode(0);
        _size = 0; 
    }
    
    int get(int index) {
        LinkNode* cur = _dummyhead;
        if(index > (_size-1) || index < 0){
            return -1;
        }
        else{
            while(index){
                cur = cur->next;
                index--;
            }
        }
        return cur->next->val;
    }
    
    void addAtHead(int val) {
        LinkNode* newNode = new LinkNode(val);
        newNode->next = _dummyhead->next;
        _dummyhead->next = newNode;
        _size++;
    }
    
    void addAtTail(int val) {
        LinkNode* newNode = new LinkNode(val);
        LinkNode* cur = _dummyhead;
        while(cur->next != nullptr){
            cur = cur->next;
        }
        cur->next = newNode;
        _size++;
    }
    
    void addAtIndex(int index, int val) {
        if(index == _size){
            addAtTail(val);
        }
        else if(index < 0){
            addAtHead(val);
        }
        else if(index > _size){
            cerr << "invalid index" << endl;
        }
        else{
            LinkNode* newNode = new LinkNode(val);
            LinkNode* cur = _dummyhead;
            while(index--){
                cur = cur->next;
            }
            newNode->next = cur->next;
            cur->next = newNode;
            _size++;
        }
    }
    
    void deleteAtIndex(int index) {
        if(index<0 || index > _size-1){
            cerr << "invalid index" << endl;
        }
        else{
            LinkNode* cur = _dummyhead;
            while(index){
                cur = cur->next;
                index--;
            }
            cur->next = cur->next->next;
            _size--;
        }
    }
private:
    int _size;
    LinkNode* _dummyhead;
};

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

学习时长

60分钟

206 反转链表

第一遍读题思考(五分钟内,如果没有思路就写暴力解法思路,暴力解法思路也不清晰就写无)

用一个while循环去遍历链表,然后用一个新的结点存储新的结果

代码随想录解法思路

双指针法,注意prev和cur指针的位置,根据prev和cur指针的位置来设置while循环的终止条件即可。但是递归的代码需要根据迭代的方式进行思路整理。具体的思考会写在下面的具体实现注意事项中。

c++代码具体实现注意事项

迭代的方法没什么注意事项,视频中的那个图画得很清晰,重点就是搞清楚每次迭代prev和cur的位置,然后判断好while的推出条件就可以。下面是基于迭代的方法的代码。

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

显然这道题的重点在于初步认识递归的代码如何写。递归首先有两个特点,一个是在主函数中只需要调用一次递归函数(在不终止的时候设置),第二是在递归函数中也调用他自己。然后针对递归函数自己,需要在函数中写出终止条件和常规操作。

```cpp
class Solution {
public:
    ListNode* reverse(ListNode* prev, ListNode* cur){
        if(cur == nullptr){
            return prev;
        }
        else{
            ListNode* tmp = cur->next;
            cur->next = prev;
            prev = cur;
            cur = tmp;
            return reverse(prev, cur);
        }
    }
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* cur = head;
        return reverse(prev, cur);  
    }
};




### 学习时长
30分钟





你可能感兴趣的:(代码随想录算法训练营第十期,链表,算法,数据结构)