题目
输入一个链表,输出该链表中倒数第k个结点。
注意:k >= 0,如果k大于链表长度,则返回 NULL;
样例
输入:链表:1->2->3->4->5 ,k=2
输出:4
思路
【1】两次循环遍历,第一次得到链表的总节点数,第二次得到所求节点。
由于单链表不能索引到前驱节点,所以只能从前往后遍历。第一次遍历得到链表总长度 n;链表的倒数第 k 个节点,相当于正数第 n−k+1个节点。所以第二次遍历到第 n−k+1个节点,就是我们要找的答案。
【2】快慢指针。快指针先走k步,然后两个指针同时走。快指针遍历链表后,慢指针所在节点即为所求。
快慢指针都由dummy开始,或者快指针由dummy慢指针由head,可画图分析具体的数值条件。
注意:
【1】考虑可能输出head节点,所以设置虚拟节点dummy
【2】考虑 k 可能大于链表长度
时间复杂度
【1】链表总共遍历两次,所以时间复杂度是 O(n)。
时间复杂度是指计算量的量级,常数会被忽略掉,比如 O(n)和 O(2n)是一样的。这个题 k≤n,所以 O(n+n−k)=O(n)
【2】快慢指针也是O(n)。
两个指针同时走不能只算一个指针的计算量。pre一共会走n步,cur一共会走n - k + 1步,一共走的次数也是 n+n−k,O(n+n-k)=O(n)。
代码v1
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def findKthToTail(self, pListHead, k):
"""
:type pListHead: ListNode
:type k: int
:rtype: ListNode
"""
if not pListHead:
return None
dummy=ListNode(0) ####考虑到可能输出head节点
dummy.next=pListHead
pre,cur=dummy,pListHead
cnt=0
while cur:
cnt+=1
cur=cur.next
if k<=cnt: #### 考虑k可能越界
for i in range(cnt-k+1):
pre=pre.next
return pre
else:
return None
代码v2
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def findKthToTail(self, pListHead, k):
"""
:type pListHead: ListNode
:type k: int
:rtype: ListNode
"""
if not pListHead:
return None
dummy=ListNode(0)
dummy.next=pListHead
pre,cur=dummy,pListHead
cnt=0
while pre and pre.next: #必须pre.next,否则若pre是尾节点,cnt多计1位None,则cnt==k无法保证k不越界
if cnt<k: #若只pre,则这里应判断cnt<k+1,return时的判断同理
pre=pre.next
else:
pre=pre.next
cur=cur.next
return cur if cnt==k else None
# return cur if cnt==k+1 else None # while pre: ...
##### while 循环内可替换为:通过k--至0,移动pre指针
while pre and pre.next:
if k>0:
pre=pre.next
k-=1
else:
pre=pre.next
cur=cur.next
return None if k else cur