直觉思路编码有bug
func removeElements(head *ListNode, val int) *ListNode {
// var pre *ListNode
// 1->2 1 // 1->1 1
// head to be deleted
for head != nil && head.Val == val {
head = head.Next
}
cur := head
for cur != nil && cur.Next != nil {
if cur.Next.Val == val {
cur.Next = cur.Next.Next
}
cur = cur.Next
}
return head
}
// 执行结果:
输入:
[1,2,2,1]
2
输出:
[1,2,1]
预期:
[1,1]
直觉思路编码fix bug
func removeElements(head *ListNode, val int) *ListNode {
// var pre *ListNode
// 1->2 1 // 1->1 1
// head to be deleted
for head != nil && head.Val == val {
head = head.Next
}
cur := head
for cur != nil && cur.Next != nil {
if cur.Next.Val == val {
cur.Next = cur.Next.Next
continue // fix bug
}
cur = cur.Next
}
return head
}
- 可以学到3点
- cur指向删除。丢失前面的节点 => 找到被删除节点前一个,就可以删除。
- 头节点没有上一个节点,所以单独处理。
- 特殊测试用例 【1,2a,2b,1】 2b的前一个节点是2a,但是cur指针没有机会移动到2a,2a就被删除了。 // fix bug。
直觉思路编码优雅fix bug
func removeElements(head *ListNode, val int) *ListNode {
// var pre *ListNode
// 1->2 1 // 1->1 1
// head to be deleted
for head != nil && head.Val == val {
head = head.Next
}
cur := head
for cur != nil && cur.Next != nil {
if cur.Next.Val == val {
cur.Next = cur.Next.Next
}else{ // fix bug by adding else
cur = cur.Next
}
}
return head
}
// 速记
- 虚拟节点统一头节点和中间节点处理逻辑
- 找到删除节点上一个节点就可以删除了。 // 每次查看next节点是不是要删除节点。// 引入dummyhead,头节点就成为next节点。
借鉴最优雅方案
func removeElements(head *ListNode, val int) *ListNode {
if head == nil{
return nil
}
// 给链表扩展一个虚拟头节点
dummy := &ListNode{Next:head}
// 遍历链表,判断下一个节点是否是被删除节点
cur := dummy
for cur.Next != nil{
if cur.Next.Val == val{
cur.Next = cur.Next.Next
}else{
cur = cur.Next
}
}
return dummy.Next
}