代码随想录Day3 | 链表01-leetcode203、707、206

203-移除链表元素

题目链接:移除链表元素

思路:链表中元素的添加和删除关键是要保证不断链且指向关系正确。对于删除操作,链的修改涉及将待删除元素的前一个元素指向待删除元素的后一个元素,因此在判断当前元素是否需要删除时,要记录当前元素的前后指针。

1.删除头结点时另作考虑

算法描述:根据上述描述,删除操作需要记录当前结点的前一个指针,而对于头结点而言没有前一个指针,因此对于将头结点单独考虑。对于后续结点,首先记录前一个结点再判断当前结点是否需要删除,若删除则将前一个结点指向当前结点的next。

/**
 * 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) {
        //删除头结点时另做考虑
        while(head != nullptr && head->val == val){
            ListNode *tmp = head;
            head = head->next;
            delete tmp;
        }
        
        ListNode *prev = head;
        while(prev != nullptr && prev->next != nullptr){
            ListNode *cur = prev->next;
            if(cur->val == val){
                prev->next = prev->next->next;
                delete cur;
            }
            else
                prev = cur;
        }
        return head;
    }
};

易错:代码中通过prev来进入循环,若当前结点需要删除,删除后对于下一个需要处理的结点的前一个结点prev仍然时当前这个,不需要进行修改。若结点不需要删除,才需要将prev向后移。

2.添加一个虚拟头结点

算法描述:添加一个虚拟的头结点,从而使得若需要删除头结点时不需要另作考虑。运算完成后返回创建的虚拟结点的next

/**
 * 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 *hnode = new ListNode(0);
        hnode->next = head;

        ListNode *prev = hnode;
        while(prev != nullptr && prev->next != nullptr){
            ListNode *cur = prev->next;
            if(cur->val == val){
                prev->next = prev->next->next;
                delete cur;
            }
            else
                prev = cur;
        }
        head = hnode->next;
        delete hnode;
        return head;
    }
};

注意:在创建虚拟结点后需要分配内存空间(第15行)


707-设计链表

链表操作的基础题,注意实现细节。不作详细说明,参考官方题解or代码随想录707.设计链表


206-反转链表

题目链接:反转链表

思路:暴力求解,定义一个新链表。但空间开销大。 --> 查看题解:代码随想录-反转链表

算法描述:双指针法,后指针确保可以按照原链表的顺序遍历下去,前指针负责修改指向关系。

        --> 三个指针记录 1)记录当前要修改的指针cur  2)记录指向原链表中的next结点的指针b_next 3)记录当前指针反转之后指向的结点pre

        --> 指针开始遍历,在开始前pre为nullptr。遍历时,首先用b_next记录当前指针的next,记录后,修改当前的cur指向为pre。更新pre和cur,继续遍历链表。

/**
 * 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 *b_next;
        ListNode *cur = head;
        ListNode *pre = nullptr;
        
        while(cur){
            b_next = cur->next; // 保存原链表中当前结点的下一个结点
            cur->next = pre; // 翻转

            pre = cur;
            cur = b_next;
        }

        return pre;

    }
};

你可能感兴趣的:(202301-代码随想录,链表,leetcode,算法,数据结构)