代码随想录训练营day3 | 203.移除链表元素 707.设计链表 206.反转链表

106 阅读2分钟

203.移除链表元素

题目链接:leetcode.cn/problems/re…

要点

  • 删除某个节点,cur指针指在其前一个节点。每次处理的是cur->next这个节点
  • 有虚拟头节点,统一了头节点、非头节点的删除逻辑

虚拟头节点写法

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

总结

移除链表元素中被移除的元素需要释放其空间,在cpp中为delete tmp;free了那部分空间。

707.设计链表

题目链接:leetcode.cn/problems/re…

要点

  • 结构体也属于类的一个属性,结构体也能有类似构造函数的
  • --++操作能并在一些赋值、条件判断语句的,就不要另起一行

带虚拟头节点写法

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

    MyLinkedList() {
        _dummyHead = new LinkedNode(0);
        _size = 0;
    }
    
    int get(int index) {
        if (index < 0 || index > (_size - 1)) {
            return -1;
        }else {
            LinkedNode* cur = _dummyHead->next;
            while (index) {
                cur = cur->next;
                index--;
            }
            return cur->val;
        }
    }
    
    void addAtHead(int val) {
        LinkedNode* newNode = new LinkedNode(val);
        newNode->next = _dummyHead->next;
        _dummyHead->next = newNode;
        _size++;
    }
    
    void addAtTail(int val) {
        LinkedNode* cur = _dummyHead;
        int size = _size;
        while (size) {
            cur = cur->next;
            size--;
        }
        LinkedNode* newNode = new LinkedNode(val);
        cur->next = newNode;
        _size++;
    }
    
    //index == _size的情况包含在 在任意位置前插入新元素 中了
    void addAtIndex(int index, int val) { 
        if (index < 0 || index > _size) {
            return;
        }
        LinkedNode* cur = _dummyHead;
        while (index) {
            cur = cur->next;
            index--;
        }
        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 = _dummyHead;
        LinkedNode* tmp;
        while (index) {
            cur = cur->next;
            index--;
        }
        tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        _size--;
    }

private:
    LinkedNode* _dummyHead;
    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);
 */

总结

get、add、delete链表的增删查操作,MyLinkedList* obj = new MyLinkedList();初始化一个实例,按照构造方法定义的方式给类的属性赋值。

206.反转链表

题目链接:leetcode.cn/problems/re…

要点

  • 双指针法依次定义pre cur tmp,其中修改指针指向是pre cur之间操作的,tmp用来连贯
  • 在每轮修改指针时,因为一旦修改了,cur往后的节点就断了,所以在修改前先更新tmp指针
    1. 记录tmp; 2. 修改指针; 3. 后移到下一个更改位置;

双指针法

/**
 * 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* pre = nullptr;
        ListNode* cur = head;
        ListNode* tmp;

        //在修改指针前,更新tmp
        while (cur) {
            //1.
            tmp = cur -> next;
            //2.
            cur -> next = pre;
            //3.
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
};

总结

反转链表双指针法包含 初始化、一轮轮的修改指针、当cur == null时返回pre 三个阶段。

中间的修改过程是相同的子问题,可写成递归的形式。