给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点,这个n保证是有效的,有两种方法:
1)第一种方法: 遍历两遍
先遍历这个链表,假设得到了这个链表的长度是L, 那么我们要删除的节点的index即是L-n+1;
再次遍历这个链表,找到要删除节点的前一个节点,删除这个节点就好了。
2)第二种方法:遍历一遍
采用两个指针,因为要删除的是这个链表倒数n个节点,先让一个指针走n个位置,之后再用一个指针,从头开始和前面的指针一起走;当前面的指针走到最后一个节点,后走的指针即是要删除的节点的前一个位置,删除节点即可。
上面的代码实现如下:
package other_pratice
/**
*
* 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点
* 这个n保证是有效的
* Author: sxy
*/
// 第一种解法,遍历两遍
// 删除链表倒数的第n个节点,假设链表的长度为L, 则删除的节点即是L-n+1个节点。
// 我们可以先遍历确定列表的长度为L、 之后找到链表的L-n节点,将它的next指针指向L-n+1的next节点
func DeleteNodeByTwoTraverse(list *NodeList, n int) *NodeList {
// 创建一个头节点,并将这个头结点指向这个list
head := NewNode(0)
head.next = list
// 得到链表长度
tmp := list
nodeLength := 0
for tmp != nil {
nodeLength++
tmp = tmp.next
}
tmp = list
count := 0
for tmp != nil {
count++
if count == (nodeLength - n) {
tmp.next = tmp.next.next
break
}
tmp = tmp.next
}
return head.next
}
// 第二种解法,遍历一遍;
// 初始化两个指针,先让第一个指针走n个index, 第二个指针才开始走,然后两个指针一起走
// 当第一个指针的next指向为nil,则第二个指针指向的位置,即是要删除节点的前一个节点
// 删除要删除的节点即可。
func DeleteNodeByOneTraverse(list *NodeList, n int) *NodeList {
head := NewNode(0)
head.next = list
pre := list
cur := list
count := 0
for pre.next != nil {
count++
if count > n {
cur = cur.next
}
pre = pre.next
}
cur.next = cur.next.next
return head.next
}
测试
package other_pratice
import (
"fmt"
"testing"
)
func TestDeleteNodeByTwoTraverse(t *testing.T) {
a := NewNode(0)
b := NewNode(2)
c := NewNode(5)
a.next = b
b.next = c
a.Print()
fmt.Println("删除后")
res := DeleteNodeByTwoTraverse(a, 2)
res.Print()
}
output
=== RUN TestDeleteNodeByTwoTraverse
0---->2---->5
删除后
0---->5
--- PASS: TestDeleteNodeByTwoTraverse (0.00s)
PASS
其实上面的代码是有问题的,没有考虑边界的问题,即有可能会删除头结点。 考虑边界的代码实现如下:
package other_pratice
import "fmt"
/**
*
* 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点
* 这个n保证是有效的
* Author: sxy
*/
// 第一种解法,遍历两遍
// 删除链表倒数的第n个节点,假设链表的长度为L, 则删除的节点即是L-n+1个节点。
// 我们可以先遍历确定列表的长度为L、 之后找到链表的L-n节点,将它的next指针指向L-n+1的next节点
func DeleteNodeByTwoTraverse(list *NodeList, n int) *NodeList {
// 创建一个头节点,并将这个头结点指向这个list
head := NewNode(0)
head.next = list
// 得到链表长度
tmp := list
nodeLength := 0
for tmp != nil {
nodeLength++
tmp = tmp.next
}
// 处理异常的情况,就是删除的节点的是倒数第L的元素,即删除链表的第一个元素
if nodeLength == n {
list = list.next
head.next = list
} else {
tmp = list
count := 0
for tmp != nil {
count++
if count == (nodeLength - n) {
tmp.next = tmp.next.next
break
}
tmp = tmp.next
}
}
return head.next
}
// 第二种解法,遍历一遍;
// 初始化两个指针,先让第一个指针走n个index, 第二个指针才开始走,然后两个指针一起走
// 当第一个指针的next指向为nil,则第二个指针指向的位置,即是要删除节点的前一个节点
// 删除要删除的节点即可。
func DeleteNodeByOneTraverse(list *NodeList, n int) *NodeList {
head := NewNode(0)
head.next = list
pre := list
cur := list
count := 0
for pre.next != nil {
count++
if count > n {
fmt.Println("count", count, "n", n)
cur = cur.next
}
pre = pre.next
}
// 处理异常情况, 当n等于count+1时,即是删除的头结点
if n == count+1 {
head.next = list.next
} else {
cur.next = cur.next.next
}
return head.next
}