嗨!小伙伴们,我们又见面啦,今天我们来一起挑战一道OJ题: 移除链表元素,准备好了吗? Ready Go !!!
![](https://i-blog.csdnimg.cn/blog_migrate/ecd4bcfb80d67fdf696449a3c97a44b4.png)
emmm,题目看上去貌似挺简单的,我们一起来分析分析吧!
思路一: 定义一个新链表,用一个pcur变量来遍历原链表的所有节点,当pcur遇到值等于val的结点,直接指向下一个结点; 当pcur遇到值不等于val的结点,就尾插到新链表中。
初始时,pcur指向原链表的头结点,新链表的头结点和尾结点都置为空。
![](https://i-blog.csdnimg.cn/blog_migrate/a7cee2ca833a8af1719c2b021c9934b7.png)
第一次:pcur指向的结点里面的数据不是val,尾插到新链表中,pcur指向下一个结点。
![](https://i-blog.csdnimg.cn/blog_migrate/c03d7b5c6c40ed8aadfea82fdfd57a28.png)
第二次: pcur指向的结点里面的数据不是val,尾插到新链表中,pcur指向下一个结点。
![](https://i-blog.csdnimg.cn/blog_migrate/2d4972419ea645337744b6247d3ebd59.png)
第三次: pcur指向的结点里面的数据是val,pcur指向下一个结点。
![](https://i-blog.csdnimg.cn/blog_migrate/56369cc0492fdf2b18877eabc333229c.png)
第四次:pcur指向的结点里面的数据不是val,尾插到新链表中,pcur指向下一个结点。
![](https://i-blog.csdnimg.cn/blog_migrate/6e1fb987fb37c94519afe15f3dc009b7.png)
第五次:pcur指向的结点里面的数据不是val,尾插到新链表中,pcur指向下一个结点。
![](https://i-blog.csdnimg.cn/blog_migrate/6875fdbc24d1deaaecb80035c1362513.png)
第六次: pcur指向的结点里面的数据不是val,尾插到新链表中,pcur指向下一个结点。
![](https://i-blog.csdnimg.cn/blog_migrate/19a54b5a2842cf2b49c470f64f16acf4.png)
pcur指向的结点里面的数据是val,pcur指向下一个结点。
![](https://i-blog.csdnimg.cn/blog_migrate/1e8dfb6959a26288173a7aaf1fc2712c.png)
此时pcur已经遍历完原链表中所有的结点,退出while循环。
好啦,现在初步理解了思想,我们一起来实现吧!
定义3个变量,newHead和newTail分别代表新链表的头结点和尾结点,初始时都为空; pcur用来遍历原链表的所有节点,初始时指向原链表的头结点。
ListNode* pcur = head; //pcur用来遍历原链表
ListNode* newHead = NULL; //新链表的头结点为空
ListNode* newTail = NULL; //新链表的尾结点为空
pcur指向头结点,进入while循环;当pcur为空,退出while循环。当pcur指向结点的值不等于val, 那么就将该节点尾插到新链表中;如果pcur指向结点的值等于val,那么pcur直接指向下一个结点。
这里请注意!链表第一次插入新结点的时候,newHead和newTail同时指向新结点,插入进来的新结点就是新链表的头结点和尾结点; 链表不为空时, 插入进来的新结点作为链表新的尾结点。
部分代码如下:
while(pcur != NULL){
if(pcur->val != val){
//结点的值不是val,就插入到新链表中
if(newTail == NULL){
//如果当前新链表为空
newHead = newTail = pcur;
}else{
// 链表不为空
newTail->next = pcur;
newTail = pcur;
}
}
//结点的值为val,pcur指向下一个结点
pcur = pcur->next;
}
然后我们返回newHead,可是力扣没有通过,这是为什么呢?
![](https://i-blog.csdnimg.cn/blog_migrate/020fbce41ae9b18a43d6c07d38e98a34.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dcadb7b4bbbbe2bf6ef18c3f5a471925.png)
哦! 我知道啦,链表的newTail的next指针应该置为空, 嗯,很不错,对了一半。
我们再去看看另外一个测试用例:
![](https://i-blog.csdnimg.cn/blog_migrate/e49c5ae1d8a3aa68c61945f33972ce42.png)
所以,我们应该先判断尾结点是否存在,如果存在,那么它的next指针为空。
整体代码如下:
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
ListNode* pcur = head; //pcur用来遍历原链表
ListNode* newHead = NULL; //新链表的头结点为空
ListNode* newTail = NULL; //新链表的尾结点为空
while(pcur != NULL){
if(pcur->val != val){
//结点的值不是val,就插入到新链表中
if(newTail == NULL){
//如果当前新链表为空
newHead = newTail = pcur;
}else{
// 链表不为空
newTail->next = pcur;
newTail = pcur;
}
}
//结点的值为val,pcur指向下一个结点
pcur = pcur->next;
}
//如果newTail存在,那么它的next指针为空
if(newTail){
newTail->next = NULL;
}
//返回新链表的头结点
return newHead;
}
好的,今天的讲解就到这里啦,我们下期再见!