力扣刷题记录六:203、移除链表元素

记录力扣刷题第六题:

本文包含C++三种解法和Python与Java的主观认为的最优解法

题目描述如下

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
如图
力扣刷题记录六:203、移除链表元素_第1张图片
来源:LeetCode

思路:

其实就是个单链表的删除操作,对数据结构有一些了解的都知道该怎么做吧。关键的一点是要注意对头节点的删除操作,如果用传统方法,只需要把head向后移即可,可是这样就需要单独写对头节点的删除函数。代码如下:

/**
 * 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) {
    	//首先写对头节点的操作
    	//注意也要判断head不为空,否则当head为空时运行会出错
    	while(head != nullptr && head->val == val) {
    	//注意这里要用while不是if,以防出现连续值等于val的节点都为头节点
    		ListNode* temp = head;
    		head = head->next;
    		//对删除的节点进行释放
    		delete temp;
    	}
    	cur = head;
    	//再写对非头节点的操作,注意while里要先判断cur不为空
    	//如果cur为空的话也就没有next,执行就会出错
    	while(cur != nullptr && cur->next != nullptr) {
    		if(cur->next->val == val) {
    			ListNode* temp = cur->next;
    			cur->next = temp->next;
    			//对删除的节点进行释放
    			delete temp;
    		}
    		else {
    			cur = cur->next;
    		}
    	}
    	return head;
    }
};

时间消耗主要用于查找到待删除节点的前一个节点,因此时间复杂度为O(n),没有额外的空间消耗,空间复杂度为O(1)。

但是对头节点和非头节点分开操作真的好麻烦呀,有没有能够将两者统一的方式呢?显然是有的,只需要在头节点前面再加一个头节点

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
    //创建一个虚拟头节点
        ListNode* VHead = new ListNode(-1);
        VHead->next = head;
        ListNode* cur = VHead;
        //cur必定不为空
        while(cur->next != nullptr) {
            if(cur->next->val == val) {
                ListNode* temp = cur->next;
                cur->next = temp->next;
                //对删除的节点进行释放
                delete temp;
            }else {
                cur = cur->next;
            }
        }
        head = VHead->next;
        //注意对自己创建的节点也要进行释放
        delete VHead;
        return head;
    }
};

时间复杂度为O(n),空间复杂度为O(1)。

这样是不是简洁美观多啦,运行时间也减少了,其实下面还有更简洁的方法,但我主观认为这是最好的解法。

下面介绍一个更简洁的方法:递归写法

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
    	if(head == nullptr) {
    		return head;
    	}
    	//递归调用removeElements
    	head->next = removeElements(head->next, val);
    	if(head->val == val) {
    		ListNode* temp = head;
    		head = head->next;
    		delete temp;
    	}
    	return head;
    }
};

时间复杂度:O(n)。
空间复杂度:由于递归调用栈,栈的层数最多不超过n层,因此为O(n)。

但链表很长时会有爆栈的风险,而且这种方法空间复杂度比较大,因此不推荐用。

所以我主观认为最好的解法还是添加头节点法。


下面放上Java和Python的添加头节点法

Java

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode VHead = new ListNode(-1);
        VHead.next = head;
        ListNode cur = VHead;
        while(cur.next != null) {
            if(cur.next.val == val) {
                cur.next = cur.next.next;
            }
            else {
                cur = cur.next;
            }
        }
        head = VHead.next;
        return head;
    }
}

Python

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
        VHead = ListNode()
        VHead.next = head
        cur = VHead
        while cur.next != None:
            if cur.next.val == val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        head = VHead.next
        return head

你可能感兴趣的:(链表,leetcode,算法)