算法随想Day3【链表】| LC203-移除链表元素、LC707-设计链表、LC206-反转链表

LC203. 移除链表元素

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

自己在做时,定义了一个虚拟头节点,然后又分别定义了ptr和prev指向迭代中当前的节点和上一个节点,定义的变量有点多,但是这种思路更容易想出且更方便个人理解。

/**
 * 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 virtual_head;  //虚拟头节点
        virtual_head.next = head;
        ListNode* prev = &virtual_head;
        ListNode* ptr = head;
        ListNode* DeleteNode;

        if (nullptr == head)
        {
            return head;
        }

        while (ptr != nullptr)
        {
            if (val == ptr->val)
            {
                prev->next = ptr->next;
                DeleteNode = ptr;
                ptr = ptr->next;
                delete DeleteNode;
            }
            else
            {
                prev = ptr;
                ptr = ptr->next;
            }
            
        }

        return virtual_head.next;
    }
};

官方解法就省去了prev和ptr这些定义,更加简洁

ListNode* removeElements(ListNode* head, int val)
{
    struct ListNode* dummyHead = new ListNode(0, head);
    struct ListNode* temp = dummyHead;
    while (temp->next != NULL) {
    if (temp->next->val == val) {
    	temp->next = temp->next->next;
    	} else {
    		temp = temp->next;
    	}
    }
    return dummyHead->next;
}
递归思路
ListNode* removeElements(ListNode* head, int val) {
	if (head == nullptr) {
		return head;
	}
	head->next = removeElements(head->next, val);
	return head->val == val ? head->next : head;
}

LC707. 设计链表

之前写得比较多,比较顺利写出来了,顺便写个demo验证下

#include <iostream>
using namespace std;

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


class MyLinkedList
{
public:
    ListNode* head;
    ListNode* tail;

    MyLinkedList()
    {
        this->head = new ListNode(0);
        this->tail = new ListNode(0);
        head->prev = nullptr;
        tail->next = nullptr;
        head->next = tail;
        tail->prev = head;
    }
    
    int get(int index)
    {
        ListNode* ptr = head->next;
        while (index-- && ptr != nullptr && ptr->next != nullptr)
        {
            ptr = ptr->next;
        }
        return ptr == nullptr ? -1 : ptr->val;
    }
    
    void addAtHead(int val)
    {
        ListNode* ptr = new ListNode(val);
        head->next->prev = ptr;
        ptr->next = head->next;
        ptr->prev = head;
        head->next = ptr;
    }
    
    void addAtTail(int val)
    {
        ListNode* ptr = new ListNode(val);
        tail->prev->next = ptr;
        ptr->prev = tail->prev;
        ptr->next = tail;
        head->prev = ptr;
    }
    
    void addAtIndex(int index, int val)
    {
        if (index < 0)
        {
            addAtHead(val);
        }
        ListNode* newNode = new ListNode(val);
        ListNode* ptr = head;
        while (index-- && ptr != nullptr && ptr->next != nullptr)
        {
            ptr = ptr->next;
        }
        if (nullptr == ptr->next)
        {
            return;
        }
        else
        {
            ptr->next->prev = newNode;
            newNode->next = ptr->next;
            newNode->prev = ptr;
            ptr->next = newNode;
        }
    }
    
    void deleteAtIndex(int index)
    {
        ListNode* ptr = head->next;
        while (index-- && ptr != nullptr && ptr->next != nullptr)
        {
            ptr = ptr->next;
        }
        if (nullptr == ptr->next )
        {
            return;
        }
        else
        {
            ptr->next->prev = ptr->prev;
            ptr->prev->next = ptr->next;
            delete ptr;
        }
    }
};

int main()
{
    MyLinkedList* linkedList = new MyLinkedList();
    linkedList->addAtHead(1);
    linkedList->addAtIndex(-3, 4);
    linkedList->addAtTail(3);
    linkedList->addAtIndex(1, 2);
    linkedList->addAtIndex(4, 2);   //链表变为4-> 2-> 1-> 3
    int a = 0;
    a = linkedList->get(1);            //返回2
    cout << a << endl;
    linkedList->deleteAtIndex(1);  //现在链表是4-> 1-> 3
    linkedList->deleteAtIndex(4);  //无效操作
    a = linkedList->get(1);            //返回1
    cout << a << endl;
}

LC206. 反转链表

之前做过,但是思路又没有了,终究是当时没有理解的透彻,而且对这类单链表的题目没有总结和思考,今天补充下,加强印象,多刷题提高。

ListNode* reverseList(ListNode* head)
{
    ListNode* curr = head;
    ListNode* prev = nullptr;
    ListNode* temp = nullptr;
    while (curr != nullptr)
    {
        ////先保存curr的next,以免改变指针指向后找不到next了
        temp = curr->next;  
        curr->next = prev;
        prev = curr;
        curr = temp;
    }

    return curr;
}

思考:

在单链表中操作某个节点时:

1、一般要有两个指针,分别记录或表示该节点前面和后面的两个节点的状态(包括头节点head,创建一个虚拟节点virtual_head置于它的前面)。

2、若需要遍历链表,一般情况下,创建一个current指针,对一条链表从头到尾做一次遍历即可,开始时判断下是使curr指向head还是virtual_head。

  • 对“LC203. 移除链表元素”这道题,创建一个virtual_head作为其虚拟头节点。curr从virtual_head开始遍历,需要移除某个匹配元素(curr->next)时,只需使curr->next = curr->next=>next即可
  • 对“LC206. 反转链表”这道题,curr从链表第一个开始遍历即可,创建一个prev记录curr的前向节点指针(对于该题目,prev应该初始化为nullptr),同时还要定义一个后向指针暂时存储curr->next
递归思路:

题解链接:https://leetcode.cn/problems/reverse-linked-list/solution/shi-pin-jiang-jie-die-dai-he-di-gui-hen-hswxy/

为什么可以使用递归:

递归接替思路:

ListNode* reverseList(ListNode* head) {
	if (head == nullptr || head->next == nullptr) return head;
	ListNode* p = reverseList(head->next);
	head->next->next = head;
	head->next = nullptr;
	return p;
}
posted @ 2023-02-03 21:15  冥紫将  阅读(25)  评论(0)    收藏  举报