四种方法解决leetcode203. 移除链表元素

更多精彩文章请关注微信公众号:TanLiuYi00

图片

本文主要针对移除单链表中的元素,提供了四种解题思路,供大家参考,希望能对大家提供帮助。

题目

图片

解法一:递归

思路:在之前的链表推文字节面试题 leetcode 83. 删除排序链表中的重复元素面试不可不会的单链表反转中都提到了链表具有天然的递归性,一个链表可以看成头节点后面挂接一个更短的(缺少头节点)的链表,同理这个更短的链表也可以看成头节点后面挂接一个更更短的链表;依次类推。本题也可采用这种思路来做,具体如下图所示。

图片

 如上图示,如果头节点是待删除的节点,则只需要将子问题求得的蓝色的链表(最下面一行的右边)返回即可,否则将子问题求得的蓝色的链表挂接在头节点后面(最下面一行的左边)返回。

Show me the Code

//  c 语言
struct ListNode* removeElements(struct ListNode* head, int val){ 
    if (head == NULL) {
        return NULL;
    }     
    /* 删除原链表中头节点后面待删除的节点 */
    head->next = removeElements(head->next, val);
    /* 头节点是待删除额节点,返回递归删除更短的链表中待删除的元素后的链表
   否则,返回将递归删除更短的链表中待删除的元素后的链表挂接在头节点后面形成的链表 */
    return head->val == val ? head->next : head;
}
# Python3
def removeElements(self, head: ListNode, val: int) -> ListNode:
    if not head: return 
    head.next = self.removeElements(head.next, val)
        return head.next if head.val == val else head

方法二:迭代

思路:删除链表中给定值的所有节点只需要两步操作,首先遍历链表查找到值为给定值的节点,然后再将查找到的这个节点的前一节点指向这个节点的下一节点。

注意点

一、查找待删除节点时,需先判断节点是否为空节点;
二、链表中的所有节点都是待删除的节点。

举栗

以链表 1->2->6->3->4->5->6,待删除的节点的值是 6 为栗子,如下图示:

图片

图片

图片

图片

图片

图片

Show me the Code


//  c++ 语言
ListNode* removeElements(ListNode* head, int val) {
    while (head != NULL && head->val == val) {
        head = head->next;
    }

    if (head == NULL) {
        return NULL;
    }
    
    ListNode* pre = head;
    while (pre->next != NULL) {
        if (pre->next->val == val) {
            pre->next = pre->next->next;
        } else {
            pre = pre->next;
        }
    }
    return head;
}
//  go 语言
func removeElements(head *ListNode, val int) *ListNode {
    for head != nil && head.Val == val {
        head = head.Next
    }
    if head == nil {
        return head
    }
    pre := head
    for pre.Next != nil {
        if pre.Next.Val == val {
            pre.Next = pre.Next.Next
        } else {
            pre = pre.Next
        }
    }
    return head
}

方法三:双指针

思路:通过两个指针 pre 和 cur(前者用于记录待删除节点的前一节点 ,后者记录当前节点 )遍历链表,如果找到待删除的节点,则将 pre 指向的节点指向 cur 指向的节点的下一个节点,并不断更新 pre 和 cur 再遍历,否则也不断更新 pre 和 cur 并不断遍历。

Show me the Code

// java
ListNode removeElements(ListNode head, int val) {
    while (head != null && head.val == val) {
        head = head.next;
    }
    
    ListNode cur = head;  //  当前节点
    ListNode pre = head;  //  保存删除节点的前一节点
    while (cur != null) {
        if (cur.val == val) {
            pre.next = cur.next;
        } else {
            pre = cur;
        }
        cur = cur.next;
    }
    return head;
}
# python3
def removeElements(self, head: ListNode, val: int) -> ListNode:
    while head and head.val == val:
        head = head.next
    pre, cur = head, head
    while cur:
        if cur.val == val:
            pre.next = cur.next
        else:
            pre = cur
        cur = cur.next
    return head

方法四:虚拟头节点

思路:前面的三种方法都需要考虑头节点是否是待删除的节点,而且删除头节点的代码的逻辑与删除非头节点的代码逻辑特别相似;可以通过在头节点前面设置虚拟头节点使得此时的头节点跟其它节点一样来避免这种情况的发生。但是需要注意最后返回的是虚拟头节点的下一节点而不是虚拟头节点。

Show me the Code

//  c++ 代码
ListNode* removeElements(ListNode* head, int val) {
    //  创建虚拟头节点
    ListNode* dummyHead = new ListNode(0);  
    dummyHead->next = head;

    ListNode* cur = dummyHead;  
    while (cur->next != NULL) {
        //  删除 cur->next
        if (cur->next->val == val) {
            ListNode* delNode = cur->next;
            cur->next = delNode->next;
            delete delNode;
        } else {
            cur = cur->next;
        }
    }
    // 由于对虚拟头节点进行了 new,相应地就需要对它的空间进行释放,防止内存泄漏
    ListNode* retNode = dummyHead->next;
    delete dummyHead;
    return retNode;
}

更多精彩​​​​​​​

请关注微信公众号TanLiuYi00

图片

猜你喜欢

转载自blog.csdn.net/Tanyongyin/article/details/113488827