我觉得在使用链表的时候一般有两种思路:一种是链表的内容可以修改,在原链表上进行处理,后续的操作不需要使用原链表的内容的时候这种思路可以节约空间和时间;另外一种是当我们不能更改链表的内容,后续需要用到的时候,这时候需要自己开辟空间。
不需要自己创建节点的方法:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
if(!head)
return head;
ListNode *tmp = head;
ListNode *pre_node = head;
ListNode *next_node = NULL;
while(tmp != NULL)
{
next_node = tmp->next;
if(tmp->val == val)
{
if(next_node)
{
tmp->val = next_node->val;
tmp->next = next_node->next;
delete next_node;
}
else
{
if(tmp == head)
{
delete head;
return NULL;
}
else
{
delete tmp;
pre_node->next = NULL;
}
}
}
else
{
pre_node = tmp;
tmp = tmp->next;
}
}
return head;
}
};
还可以看到有更加优雅的方法:它直接获取存head的这个指针的地址,然后通过修改head的指针的存储地址来删除。不过我有疑惑,这种方法会不会导致内存泄漏,毕竟它没有显示地delete这些节点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *removeElements(ListNode *head, int val)
{
ListNode **list = &head;
while (*list != nullptr)
{
if ((*list)->val == val)
{
*list = (*list)->next;
}
else
{
list = &(*list)->next;
}
}
return head;
}
};
递归做法:这方面我还得学习一个。
public ListNode removeElements(ListNode head, int val) {
if (head == null) return null;
head.next = removeElements(head.next, val);
return head.val == val ? head.next : head;
}