一、写在前面
在刷leetcode的一些常见考试题目的时候,做到leetcode83题,想起来之前自己写剑指的时候遇到过一个类似的题目,所以把这两个题目放在一起对比一下。
二、leetcode83
(1)题目描述
(2)通过代码
/**
* 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) {
ListNode*p=head;
while(p&&p->next)
{
if(p->val==p->next->val)
p->next=p->next->next;
else
p=p->next;
}
return head;
}
};
(3)解题思路
链表的很多题目都是需要通过指针的移动来对其中的结点元素进行操作,所以最重要的是要想清楚指针应该怎么移动。像这个题目,题目要求保留重复结点中的一个结点。while(p&&p->next)循环的意思是每次只有当前结点和下一个结点都不是空节点才进入循环,因为如果下一个结点已经是空节点了,此时当前结点就没有重复的结点,也就不需要再进行任何的操作,直接退出循环就好。而每次进入循环的操作,都是先判断当前结点p的值是否等于下一个结点p->next的值,相等的话,就说明此时需要移动指针,通过p->next=p->next->next来删除下一个结点;如果不相等的话,就说明暂时还不需要移动指针,就通过p=p->next使得p指向下一个结点,继续循环操作判断下一个结点就好。
三、剑指56
(1)题目描述
(2)通过代码
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
ListNode*head=new ListNode(-1);
head->next=pHead;
ListNode*p=head;
ListNode*pre=p;
if(pHead==NULL)
return NULL;
while(p&&p->next)
{
if(p->val==p->next->val)
{
while(p->next&&p->val==p->next->val)
p=p->next;
p=p->next;
pre->next=p;
}
else
{
pre=p;
p=p->next;
}
}
return head->next;
}
};
(3)解题思路
这道题应该算是上面leetcode83的进阶版本吧。这里的思路跟上面就不一样,因为是需要删除所有的重复结点,所以就不能像上面leetcode83那样通过p->next=p->next->next来删除,只能每次找到当前重复结点的下一个结点,同时每次记录上一次的结点pre,再通过pre->next=p将上一个结点和重复结点的下一个结点关联在一起。而如果当前结点没有重复结点,此时就可以得到pre用来记录当前结点,同时移动p指针继续向前。
思路理清了,在做的时候还是遇到了很多问题。刚开始我发现输入[1,1,1]作为链表,程序总是崩溃。在想了很久以后,才发现错在while(p->next&&p->val==p->next->val)
这一句,我之前写的是while(p->val==p->next->val)
,这样的话就没有考虑到当p->next为NULL的情况,如果p->next为NULL,遇到[1,1,1]这种链表就必定会崩溃,因为NULL不存在val。
这道题还有一个注意点是,刚开始要创建一个头结点head,将head指向pHead结点,然后进行操作,这是为了避免删除第一个结点的情况,如果第一个结点就是重复结点,那么就不太好删除,所以添加一个头结点,最后再返回head的下一个结点head->next。