今天来看一道有意思的链表算法题目。
给到一个单向链表,要求找出该链表中倒数第 k 个节点,要求只能遍历一次链表,且空间复杂度为 O(1)。
思路1:如果能从链表尾部开始遍历,那只需倒序遍历 k 个节点即是要找出的节点,但是由于是单链表,只能从头结点开始遍历。
思路2:先遍历一遍该单链表,获取链表的总节点数 n,那么第 n-k+1 这个节点就是倒数第 k 个节点。所以第二次再遍历到第 n-k+1 这个节点即可,但是题目要求只能遍历一遍链表。
思路3:通过遍历该链表把节点都存入到一个数组中,然后再通过数组下标可直接获取到倒数第 k 个节点,但是这样会需要额外的存储空间,空间复杂度为 O(n)。
上面这三种常规思路其实都是不符合题目要求的,那就只能想其他办法了。
我们知道,链表的节点之间都是通过指针来连接的,我们先额外定义两个空指针,分别叫前指针和后指针。
先让前指针指向链表的头指针并开始遍历,一直遍历到第 k-1 个节点,在这期间,后指针原地保持不动。
当前指针遍历到第 k 个节点时,后指针也指向链表头指针并开始遍历,在这之后,前指针每往后遍历一个节点,后指针也往后遍历一个节点。
这样前后两指针的距离始终都保持为 k-1,当前指针遍历到链表的最后一个节点时,后指针刚好也就到了倒数第 k 个节点了。
如果还没想明白的话,看下面的图应该就很好理解了。p1 代表前指针,p2 代表后指针,该链表一共有 6 个节点,要求的是倒数第 3 个节点。
当然这只是题目的解决思路,实际用代码来实现这个算法,还有一些需要特别注意的地方。
比如头指针不能为空,k 不能等于 0,k 不能大于链表的总节点数。这些都是需要我们在代码中考虑到的情况,下面附上一份用 python 实现该算法的代码。