(1)删除链表中的节点
pre初始化为虚拟头结点,cur初始化为pHead,遍历链表时如果查到该节点,pre->next=cur->next;
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @param val int整型
* @return ListNode类
*/
ListNode* deleteNode(ListNode* head, int val) {
// write code here
ListNode *fakeHead= new ListNode(-1);
fakeHead->next=head;
ListNode *pre=fakeHead;
ListNode *cur=pre->next;
while(cur){
if(cur->val==val){
pre->next=cur->next;
break;
}
pre=pre->next;
cur=cur->next;
}
return fakeHead->next;
}
};
(2)NC25 删除有序链表中重复的元素-I
原题链接:https://www.nowcoder.com/practice/c087914fae584da886a0091e877f2c79
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @return ListNode类
*/
ListNode* deleteDuplicates(ListNode* head) {
// write code here
//链表为空直接返回
if(head==nullptr) return head;
ListNode *p=head;
while(p->next!=nullptr){
if(p->val==p->next->val) p->next=p->next->next;
else p=p->next;
}
return head;
}
};
(3)NC24 删除有序链表中重复的元素-II
原题链接:https://www.nowcoder.com/practice/71cef9f8b5564579bf7ed93fbe0b2024
与上题不同之处在于:上一题要如果出现重复的元素那么只留一个,此题如果出现重复的元素那么一个都不留,要删除所有重复的元素
解法一(双指针):
我们已经用newhead来帮助我们解决了第一个元素是重复元素的问题,还没有解决最后一个节点是重复节点的问题。
在此做以解释:因为每次我们都要用cur->val与cur->next->val进行比较,所以cur->next不能为空,所以while循环的条件里是while(cur&&cur->next)
。但如果最后一个元素重复即cur->val=cur->next->val
(如图中的…->3->3->null),在此情况下按照上图的步骤,我们只修改了cur的next指针为cur->next->next(如上图中⑤的第一个图),在下一次循环中才会对pre的next指针进行修改,但此时已经跳出循环!所以这种情况要单独对最后一个pre->next进行赋值。
这里一定要明确pre指针、cur指针的意义:
- pre记录上一步中的非重复元素,即会出现在最终结果中的节点
- cur则计算pre的next指针应指向哪一个元素(即cur用来判断当前节点是否应当被加入答案链表中)
当前节点=下一个节点值时,更新cur的next指针判断后面是否也是重复的节点
- …2(pre)->3(cur)->3->3->null,修改cur的next指针
cur->next=cur->next->next;
,变为…2(pre)->3(cur)->3->null(虽然还存在重复节点,但是会在下一次循环中进行修改)
当前节点≠下一个节点值时,有两种情况:
- cur此时是重复节点: …2(pre)->3->3(cur)->4->null,要完全删除重复节点即
pre->next=cur->next
- cur此时不是重复节点:…2->3->3(pre)->4(cur)->null,将cur加入答案链表即
pre=cur
这样不断地通过pre找到非重复元素,经过cur的连接就构成了新的结果链表,由于我们新建了一个newhead作为虚拟的头节点,所以结果链表的头节点变为newhead->next。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @return ListNode类
*/
ListNode* deleteDuplicates(ListNode* head) {
// write code here
ListNode *fakehead = new ListNode(-1);
fakehead ->next=head;
ListNode *pre=fakehead;
ListNode *cur=pre->next;
int count=0;
while(cur&&cur->next){
//判断当前节点cur和下一个节点是否相同,则进行处理:跳过下一个节点进行连接
if(cur->val==cur->next->val){
cur->next=cur->next->next;
//标记cur为重复节点
count++;
}else{//cur的值和下一个节点不同,则判断cur是否应被加入答案
//count>0说明cur为重复节点,应删除cur
if(count>0) {
pre->next=cur->next;//pre->next要跳过cur
count=0;
}
//cur不是重复节点,则将pre顺次后移(将cur放入答案链表中)
else pre=cur;
//无论哪种情况,只要当前和下一个不相等,cur就后移更新
cur=cur->next;
}
}
//当最后一个点是重复节点,给pre->next赋值
if(count>=0) pre->next=cur->next;
return fakehead->next;
}
};
注:这里的特殊情况就是head=nullptr,由于我们设置了newhead->next=head,所以newhead->next = nullptr,此情况不会进入任何一个程序段会直接返回newhead->next即nullptr。所以无需单独提出来进行处理
解法二(递归):
当head后面存在值且与head的值相等的话,那么就一直向后找,直到找到不相等的值为止,此时跳出查找的循环,得到一个非重复的元素。对于后面的结点也是应该进行这样的操作,即循环向后遍历直到找到一个非重复的元素。这个过程都是相似的所以可以进行递归操作:如果head的值与head->next的值不相等的话,那么就递归后面的结点,再使用head->next = deleteDuplicates(head->next);
的操作将下层返回的节点进行连接,最后返回第一层的head即可。图示如下:
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @return ListNode类
*/
ListNode* deleteDuplicates(ListNode* head) {
// write code here
if(head==nullptr) return head; //递归结束条件
if(head->next!=nullptr && head->val == head->next->val){
while(head->next!=nullptr && head->val == head->next->val)
head = head->next;
return deleteDuplicates(head->next);
}
head->next = deleteDuplicates(head->next);
return head;
}
};
两种方法的对比: