题干:给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
如果没有快慢指针的思想, 我可能就是通过遍历两遍来解决。第一次遍历得到链表的长度,然后第二次遍历到相应的地方,然后进行删除。
在做过了求解链表中间节点及链表是否有环的问题后就会接触到快慢指针,很自然的想到本题也可以用快慢指针的思想解答。
具体代码如下:
fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? {
// leetcode题目一定要注意参数合法性
if (head == null) {
return head
}
// 构建一个哑节点,方便处理一些特殊情况,如删除第一个节点。
var dummyNode = ListNode(0)
dummyNode.next = head
// 定义一个慢指针和一个快指针
var slow: ListNode? = dummyNode
var fast: ListNode? = dummyNode
// 快的先走n步,让快指针与慢指针之间的距离拉开为n。
// for的取值为[0, n] 左右都是闭区间。(故实际是快慢指针之前的距离是n + 1,这样是因为让slow指向待删除的前一个节点。如果此处的区间不包括n,那么后面遍历完成时slow正好指向待删除元素。)
for (i in 0..n) {
fast = fast?.next
}
// 让快慢指针同时向后遍历,当快指针为空时,慢指针正好指向待删除节点的前一个节点。
while (fast != null) {
fast = fast.next
slow = slow?.next
}
// 此时slow是待删除节点的前一个节点
slow?.next = slow?.next?.next
return dummyNode.next
}
如此,使用快慢指针则只用遍历一次链表即可。