[剑指offer] 22.链表中倒数第k个节点

题目

输入一个链表,输出该链表中倒数第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               
                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值