链表的含义不在过多赘述,我在开头提一下,对于链表的操作而言实际上是指针的操作,明白这个就简单很多了,还有就是一个头指针是必须的但是头节点不是必须的,因为假设没有头指针那么根本无法开始下一步操作,
题意:删除链表中等于给定值 val 的所有节点。
示例 1: 输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]
示例 2: 输入:head = [], val = 1 输出:[]
示例 3: 输入:head = [7,7,7,7], val = 7 输出:[]
审题来看,就是删除给定值即可,首先想到暴力解法循环,遍历找出每一个指定值,然后将其上一个指针直接连到下一个节点即可。
可以先写出链表的简单定义,后续链表的初始化基本都是这样写的,
struct ListNode
{
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
然后看看题设给的代码是什么?
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
}
};
它给了个头指针和指定值,注意在链表的操作中,一般情况下来设置一个虚拟头节点可以方便我们操作,但是要遍历的时候需要注意遍历条件:
ListNode* dummyHead = new ListNode(0);
dummyHead ->next = head;
ListNode *cur = dummyHead;
同时注意把虚拟头结点的下一位指向我们的链表头节点,然后设置一个移动指针进行遍历。
接下来就是循环,注意循环结束条件,很明显如果链表到最后了,那么他的下一个指针一定是空的,因此循环条件为:
cur->next != NULL
后面就是简单的移动过程了,链表节点移动是cur = cur -> next;然后在移动的过程中判断val值是否等于给定值,如果相等直接指针跳到下一位即可,代码如下:
while (cur->next != NULL)
{
if (cur->next->val == val)
{
cur->next = cur->next->next;
}else
cur = cur ->next;
}
//注意这个返回值,这个虚拟头节点是我们自己设置的虚拟值为0,按理说应该返回原本删除后的链表是没有这个虚拟节点的。
return dummyHead ->next;
上面的方法是我们用添加了虚拟头节点的方法来的,这个好处就是我们不需要去额外判断这个头节点到底是不是给定值,而是直接都一起循环就完事了。下来我们看看如果使用传统方法来的话,首先我们需要判断头节点是不是?
while (head ->val == val)
{
//head ->next = head ->next ->next;
head = head ->next;
}
我这里多写了一行代码,注意区别,其实也就是删除头节点和其他节点的区别,对于头节点而言,我们直接把他的下一位作为头指针即可,也就是头指针移动到下一位的意思。对于其他节点,那就需要跳过那个节点,然后把下下位赋予这个节点的下一位,
对于非头节点而言就很显而易见了跟前面一模一样,在这里就不再过多赘述。
还是那句话,指针弄明白了链表就清楚了。