这道题也是考察链表的操作,删除链表中的元素非常简单,只要将前一个链表节点的指针指向下一个链表节点就好了。所以,下面这段程序就可以实现这个方法。通过程序我们也可以看出,在链表中任意位置插入删除元素,都不需要变动链表中其他的元素,而数组则需要把后面的元素整体向前移动一位。这就是链表相比于数组的另一大优势。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head == nullptr) return head;
ListNode* p1=head;
while(p1->next!=nullptr){
if(p1->val == p1->next->val){
p1->next=p1->next->next;
}
else{
p1=p1->next;
}
}
return head;
}
};
这样的程序是可以跑通的,在leetcode也可以提交,但是存在一个非常危险的漏洞!实际应用的时候,千万不能像这样编写程序。
我们观察到,p1->next=p1->next->next代码执行之后,原来的p1->next变量虽然在堆中存在,但是栈中已经没有指向它的指针了!也就意味着,这个变量无法再次在程序中使用,却仍然占用着系统的内存空间。leetcode在做完每个实例时会自动初始化一遍程序,所以可以通过,实际应用时,这些无法访问到的堆内存变量就会在内存中无限堆积,如果程序不结束,这样做最终必然导致内存不足。
C++中,堆内存中的元素如果不用,就必须使用delete方法来删除。所以程序需要像这样改进。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head == nullptr) return head;
ListNode* p1=head;
while(p1->next!=nullptr){
if(p1->val == p1->next->val){
ListNode* temp=p1->next;//先备份一下p1->next的指针
p1->next=p1->next->next;
delete temp; //p1->next不再使用,将它从堆中删除
}
else{
p1=p1->next;
}
}
return head;
}
};
总之C++使用堆内存还是需要注意的,尤其是记住堆内存中的变量如果不再使用必须使用delete删除,以避免出现访问不到的内存垃圾。而大多数语言比如java,python由于有了自动垃圾回收机制,只需要让虚拟机自动删除这些变量就好了。