【算法】链表中倒数第k个节点

58 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情

题目

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。

解题思路

已知给到k值,此值是链表尾部向前数的值来求得对应节点。单向链表只能正向遍历查询,无法直接从链表尾部查询到某个节点。

遍历解法

链表结构特殊性无法只知道链表总长度,因此先遍历链表获取链表长度。

  1. 知道链表长度后,已知k值是反向的,其次知道了链表总长度。
  2. 从而通过k值和链表总长度得到正向遍历时的下标位置。
  3. while(count - k)再次遍历链表所求获取节点。
    public ListNode getKthFromEnd(ListNode head, int k) {

            // 1.巧解 反向思考 -
            // 先知道链表长度
            // 根据下标正向遍历知道
            ListNode first = head;
            int count = 1;
            while(first.next != null){
                first = first.next;
                count ++;
            }
            while((count - k) >0){
                head = head.next;
                count--;
            }
            return head;
    }

双指针解法

双指针和遍历解法有点相像,但双指针不需要遍历整个链表获取长度。

  1. 首先move指针先移动k-1次。
  2. 然后再同时移动move指针和left指针,直到move移动到链表结束为止。
  3. 返回slow当前节点就是k值倒数链表所指的节点了。

第二次循环移动和遍历解法是一样,slow正向移动(count - k)到达指定节点。

思考一下:move先移动就是为了减去k-1个节点数,再移动时就是去移动剩下正向移动所指想节点的位置了。

    public ListNode getKthFromEnd(ListNode head, int k) {
			ListNode move = head; 
            ListNode slow = head;
            
            while(k > 1){
                move = move.next;
                k --;
            }
            while(move.next != null){
                move = move.next;
                slow = slow.next;
            }
            return slow;
    }

参考