day003-链表-移除链表元素、设计链表、设计链表

203.移除链表元素

题目建议:本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。

题目链接/文章讲解/视频讲解

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

思路

虚拟头结点,没啥难度。leetcode里默认原结点都是用new创建的,所以都可以用delete删除。
时间复杂度O(n)
空间复杂度O(1)

注意

创建虚拟头结点记得new,删除节点 记得delete。

707.设计链表

建议: 这是一道考察 链表综合操作的题目,不算容易,可以练一练 使用虚拟头结点

题目链接/文章讲解/视频讲解

class MyLinkedList {

public:
    
    struct LinkedNode {
        int val;
        LinkedNode* next;
        LinkedNode() : val(0), next(NULL) {}
        LinkedNode(int x) : val(x), next(NULL) {}
        LinkedNode(int x, LinkedNode* next) : val(x), next(next) {}
    };

    MyLinkedList() {
        _dummyHead = new LinkedNode(0);
        _size = 0;
    }

    int get(int index) {
        if (index > (_size - 1) || index < 0) {
            return -1;
        }
        LinkedNode* cur = _dummyHead;
        for (int i = 0; i <= index; i++) {
            cur = cur->next;
            
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        LinkedNode* temp = new LinkedNode(val, _dummyHead->next);
        _dummyHead->next = temp;
        _size++;

    }
    
    void addAtTail(int val) {
        LinkedNode* cur = _dummyHead;
        while(cur->next != NULL){
            cur = cur->next;
        }
        LinkedNode* tmp = new LinkedNode(val);
        cur->next = tmp;
        _size++;
    }
    
    void addAtIndex(int index, int val) {

        if (index <= 0) addAtHead(val);
        else if (index > _size) return;
        else if (index == _size) addAtTail(val);
        else if (index <= _size - 1) {
            LinkedNode* cur = _dummyHead;
            for (int i = 0; i < index; i++) {
                cur = cur->next;
            }
            LinkedNode* tmp = new LinkedNode(val);
            tmp->next = cur->next;
            cur->next = tmp;
            _size++;
        }
        
    }
    
    void deleteAtIndex(int index) {
        if (index >= 0 && index < _size) {
            LinkedNode* cur = _dummyHead;
            for (int i = 0; i < index; i++) {
                cur = cur->next;
            }
            LinkedNode* tmp = cur->next;
            cur->next = cur->next->next;
            delete tmp;
            _size--;
        }
    }

private:
    int _size;
    LinkedNode* _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);
 */

思路

先建立节点结构体,一步步设计,思想上不难。
时间复杂度O()
空间复杂度O()

注意

有很多小坑需要注意,五分钟写完了代码,结果调报错挑了一个小时几乎,最后发现是多写了一个大括号,非常的崩溃。还是对代码不够敏感和熟练的原因。记得第一次写这题时也是类似的非常小的错误,导致排查了非常久,实在是很不应该,也实在是需要更注意更留心,尤其要着重培养根据报错思考错误的可能性原因,不能只往代码逻辑上排查问题。
python写太多了,尤其要注意其中与C++的语法区别,包括声明,顺序等等。
首先是private部分里有用到结构体,所以必须放到后面写。
括号一定要一一对应好。
一些明显不合理的报错大概率都是不小心的拼写错误,或者语法、符号标点问题,要详细检查。

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* reverse(ListNode* p, ListNode*q) {
        if (q == NULL) return p;
        ListNode* qq = q->next;
        q->next = p;
        return reverse(q, qq);
    }
    ListNode* reverseList(ListNode* head) {
        return reverse(NULL, head);
    }
};

迭代法

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* p = NULL;
        ListNode* cur = head;
        ListNode* q;
        while (cur != NULL) {
            q = cur->next;
            cur->next = p;
            p = cur;
            cur = q;
        }
        return p;
    }
};

思路

第一想法是三个指针,p, cur, q 分别保存结点的前,自身,后。然后一个个遍历过去,会稍微麻烦一点。
后来瞥到一眼之前的答案,是递归,就写成了递归的形式,毕竟写起来比较简单。
思路上并没有第一时间想到递归。对于相同操作的遍历等,都应到第一时间联想到递归。
时间复杂度O(n)
空间复杂度O(n)

迭代法
时间复杂度O(n)
空间复杂度O(1)

注意

注意三指针的迭代法与递归法都是O(n)的时间复杂度,但是迭代法空间复杂度为O(1),更优。迭代法要注意最后返回的是p结点,因为当前所在的cur结点已经是空节点。

你可能感兴趣的:(链表,数据结构,leetcode)