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

链表理论基础

文章链接

单链表

只能向后查询

链表1

双链表

可以双向查询

链表2

循环链表

首尾链接

链表4

链表的存储方式

链表在内存中不需要是连续分布的!和数组不同!

链表通过指针域的指针链接在内存中的各个节点,所以可以散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。

链表的定义

C/C++定义链表节点:

struct ListNode {
    int val; // value of the node
    ListNode* next; // pointer points to the next node
    ListNode(int x): val(x), next(NULL) {} // construct function, initialize val and assign next to NULL
};

定义构造函数可以让你初始化节点:

ListNode* head = new ListNode(5);

如果使用C++默认构造函数,在初始化时不可以直接给变量赋值

ListNode* head = new ListNode();
head->val = 5;

链表的操作

删除节点

链表-删除节点

把C的next指针指向E,把D的指针断开并手动释放D。

在Java,Python等语言中有自己的内存回收机制,不需要自己手动释放。

添加节点

链表-添加节点

C的next指针指向F,F的next指针指向D。

添加和删除都是O(1),但是要是删除最后一个节点,查找的复杂度是O(N)。

性能分析

链表-链表与数据性能对比

数组的长度是固定的!想改长度只能新建一个新数组!

链表的长度是不固定的,可以动态删减,适用于频繁删减较少查询的场景。

203.移除链表元素 Remove Linked List Elements

题目链接  |  文章链接  |  视频链接 

需要把删除head和删除其他元素分开讨论,但也可以使用虚拟头节点的方式进行统一删除法

C解法

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


struct ListNode* removeElements(struct ListNode* head, int val){

    struct ListNode* temp = head;
    while (head && head->val == val){
        temp = head;
        head = head->next;
        temp->next = NULL;
        free(temp);
    }

    struct ListNode* node = head;

    while (node && node->next){
        while (node->next && node->next->val == val){
            temp = node->next;
            node->next = node->next->next;
            temp->next = NULL;
            free(temp);
        }
        node = node->next;
    }

    return head;
}

C++解法

/**
 * 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* temp;
        while (head && head->val == val){
            temp = head;
            head = head->next;
            temp->next = NULL;
            delete temp;
        }

        ListNode* node = head;

        while (node && node->next){
            while (node->next && node->next->val == val){
                temp = node->next;
                node->next = node->next->next;
                temp->next = NULL;
                delete temp;
            }
            node = node->next;
        }

        return head;
    }
};

Python解法

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def removeElements(self, head, val):
        """
        :type head: ListNode
        :type val: int
        :rtype: ListNode
        """

        while (head and head.val == val):
            head = head.next

        node = head
        while (node and node.next):
            while (node.next and node.next.val == val):
                node.next = node.next.next

            node = node.next
        
        return head

虚拟头节点

Python解法

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def removeElements(self, head, val):
        """
        :type head: ListNode
        :type val: int
        :rtype: ListNode
        """

        dummpyhead = ListNode(next = head)

        node = dummpyhead

        while (node and node.next):
            while (node.next and node.next.val == val):
                node.next = node.next.next

            node = node.next
        
        return dummpyhead.next

707.设计链表 Design Linked List

题目链接  |  文章链接  |  视频链接  |  官方解答

单向链表

需要什么?

  • 定义节点,每个节点需要:
    • val 储存的值
    • next 指向下一个节点的指针
  • 一个虚拟头,Leetcode官方称之为哨兵(sentinel)
  • 一个size参数保存有效节点 (有助于进行与index相关的操作时可以先行判定index的validity

img

 定义节点的方式有很多种:

  • 新建一个class
  • 或者在现有的MyLinkedList里定义一个struct

虚拟头和size则为MyLinkedList Class的variable

一些需要注意的C++ Convention:

The public, protected, and private sections of a class are to be declared in that order (the public section is declared before the protected section which is declared before the private section).

C++解法

要注意addAtIndex这个function的用法,当index==length,操作如同addAtTail

class MyLinkedList {
public:
    MyLinkedList() {
        head = new ListNode();
        size = 0;
    }
    
    int get(int index) {
        if (index < 0 || index > size - 1) {
            return -1;
        } else {
            ListNode* current = head->next;
            while (index--){
                current = current->next;
            }
            return current->val;
        }
    }
    
    void addAtHead(int val) {
        // our "head" is not the real head!!!
        if (val <= 1000){
            ListNode* newHead = new ListNode(val);
            newHead->next = head->next;
            head->next = newHead;
            size++;
        }
    }
    
    void addAtTail(int val) {
        if (val <= 1000){
            ListNode* newTail = new ListNode(val);
            ListNode* current = head;
            while (current->next){
                current = current->next;
            }
            current->next = newTail;
            size++;
        }
    }
    
    void addAtIndex(int index, int val) {
    /** Add a node of value val before the indexth node in the linked list. 
     *  If index equals the length of the linked list, the node will be appended 
     *  to the end of the linked list. If index is greater than the length, 
     *  the node will not be inserted.
    **/
        if (index < 0 || index > size) {
            return;
        } else if (val <= 1000) {
            ListNode* current = head;
            while (index--){
                current = current->next;
            }
            ListNode* newNode = new ListNode(val);
            newNode->next = current->next;
            current->next = newNode;
            size++;
        }
    }
    
    void deleteAtIndex(int index) {
        if (index < 0 || index > size - 1) {
            return;
        } else {
            ListNode* current = head;
            while (index--){
                current = current->next;
            }
            ListNode* deleteNode = current->next;
            current->next = deleteNode->next;
            delete deleteNode;
            size--;
        }
    }

private:
    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) {}
    };
    ListNode* head;
    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的定义很重要!!!

typedef struct MyLinkedList {
    int val;
    struct MyLinkedList* next;    
} MyLinkedList;


MyLinkedList* myLinkedListCreate() {
    MyLinkedList* head = (MyLinkedList*) malloc (sizeof(MyLinkedList));
    head->val = 0;
    head->next = NULL;
    return head;
}

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

void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    if (val <= 1000){
        MyLinkedList* newObj = (MyLinkedList*) malloc (sizeof(MyLinkedList));
        newObj->val = val;
        newObj->next = obj->next;
        obj->next = newObj;
        obj->val++;
    }
}

void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    if (val <= 1000){
        MyLinkedList* current = obj;
        MyLinkedList* newObj = (MyLinkedList*) malloc (sizeof(MyLinkedList));
        newObj->val = val;
        newObj->next = NULL;
        while (current->next){
            current = current->next;
        }
        current->next = newObj;
        obj->val++;
    }
}

void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    int size = obj->val;
    if (index < 0 || index > size){
        return;
    } else if (val <= 1000){
        MyLinkedList* current = obj;
        MyLinkedList* newObj = (MyLinkedList*) malloc (sizeof(MyLinkedList));
        newObj->val = val;
        newObj->next = NULL;
        while (index--){
            current = current->next;
        }
        newObj->next = current->next;
        current->next = newObj;
        obj->val++;
    }
}

void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    int size = obj->val;
    if (index < 0 || index > size - 1){
        return;
    } else {
        MyLinkedList* current = obj;
        while (index--){
            current = current->next;
        }
        MyLinkedList* deleteNode = current->next;
        current->next = current->next->next;
        deleteNode->next = NULL;
        free(deleteNode);
        obj->val--;
    }

}

void myLinkedListFree(MyLinkedList* obj) {
    while (obj){
        MyLinkedList* deleteNode = obj;
        obj = obj->next;
        deleteNode->next = NULL;
        free(deleteNode);
    }
}

/**
 * Your MyLinkedList struct will be instantiated and called as such:
 * MyLinkedList* obj = myLinkedListCreate();
 * int param_1 = myLinkedListGet(obj, index);
 
 * myLinkedListAddAtHead(obj, val);
 
 * myLinkedListAddAtTail(obj, val);
 
 * myLinkedListAddAtIndex(obj, index, val);
 
 * myLinkedListDeleteAtIndex(obj, index);
 
 * myLinkedListFree(obj);
*/

Python解法

class ListNode:
    def __init__(self, val):
        self.val = val
        self.next = None

class MyLinkedList(object):

    def __init__(self):
        self.head = ListNode(0)
        self.size = 0

    def get(self, index):
        """
        :type index: int
        :rtype: int
        """
        if (index < 0 or index > self.size - 1):
            return -1
        else:
            curr = self.head.next
            while index:
                curr = curr.next
                index -= 1
            return curr.val

    def addAtHead(self, val):
        """
        :type val: int
        :rtype: None
        """
        if val <= 1000:
            new = ListNode(val)
            new.next = self.head.next
            self.head.next = new
            self.size += 1

    def addAtTail(self, val):
        """
        :type val: int
        :rtype: None
        """
        if val <= 1000:
            curr = self.head
            while (curr.next):
                curr = curr.next
            curr.next = ListNode(val)
            self.size += 1

    def addAtIndex(self, index, val):
        """
        :type index: int
        :type val: int
        :rtype: None
        """
        if (index < 0 or index > self.size):
            return
        elif val <= 1000:
            curr = self.head
            while index:
                index -= 1
                curr = curr.next
            new = ListNode(val)
            new.next = curr.next
            curr.next = new
            self.size += 1

    def deleteAtIndex(self, index):
        """
        :type index: int
        :rtype: None
        """
        if (index < 0 or index > self.size - 1):
            return
        else:
            curr = self.head
            while index:
                index -= 1
                curr = curr.next
            delete = curr.next
            curr.next = curr.next.next
            self.size -= 1

# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)

双指针写法可参照Leetcode官方解答:官方解答

206.反转链表 Reverse Linked List

题目链接  |  文章链接  |  视频链接

代码随想录文章里的动图可以很直观的展现这个题的解法

 反转指针:

C++解法

 

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

C解法

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


struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* temp;
    struct ListNode* curr = head;
    struct ListNode* prev = NULL;
    while (curr) {
        temp = curr->next;
        curr->next = prev;
        prev = curr;
        curr = temp;
    }
    return prev;
}

Python解法

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        curr = head
        prev = None
        while (curr):
            temp = curr.next
            curr.next = prev
            prev = curr
            curr = temp
        return prev

递归法

C++解法

/**
 * 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* reverser(ListNode* prev, ListNode* curr){
        if (!curr) return prev;
        ListNode* temp = curr->next;
        curr->next = prev;
        return reverser(curr, temp);
    }

    ListNode* reverseList(ListNode* head) {
        return reverser(nullptr, head);
    }
};

C解法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverse(struct ListNode* prev, struct ListNode* curr){
    if (!curr){
        return prev;
    }
    struct ListNode* temp = curr->next;
    curr->next = prev;
    return reverse(curr, temp);
}

struct ListNode* reverseList(struct ListNode* head){
    return reverse(NULL, head);
}

Python解法

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def reverse(self, prev, curr):
        if not curr:
            return prev
        temp = curr.next
        curr.next = prev
        return self.reverse(curr, temp)

    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        return self.reverse(None, head)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值