链表中倒数第K个节点

128 阅读2分钟

原题在这里哈

题目:输入一个链表,输出该链表中倒数第k个节点

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

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

1、先明白一点:每个节点都会next指向下一个节点

  • 头部节点为1,但是它next指向了2,2又指向了3 . . . . ,所以头部节点的形式为:[1,2,3,4,5]
  • 第二个节点自然为:[2,3,4,5]
  • 所以倒数第K个节点就是:[4,5]

2、力扣上我们只需要写函数接口就可以,链表指针等都是封装好了


这道题有三种做法:

做法一:利用数组

  • 将链表的每个节点包括其链接的节点存储到数组中
  • 再利用数组索引取出来
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var getKthFromEnd = function(head, k) {
    let h = head
    let arr = []
    while(h) {
        // 每次都将节点存储到数组的头部
        arr.unshift(h)
        h = h.next
    }
    return arr[k-1]
};

img

做法二:利用单指针

  • 定义一个指针,统计链表的长度n
  • 然后再返回链表的第n-k个节点
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var getKthFromEnd = function(head, k) {
    // 定义一个指针 指向头部节点
    let h = head
    let n = 0
    while (h) {
        h = h.next
        n++
    }
    // 此时指针指向最后一个节点的下一个节点 null,所以需要手动将指针指向头节点
    let h = head
    while (n - k > 0) {
        h = h.next
        n--
    }
    return h
};

img

效率一般般哈

3、快慢双指针

  • 定义一个慢指针 和 一个快指针,都指向头部节点

    img

  • 让快指针先走 k 步,然后慢指针再跟着快指针一起移动

    img

  • 当快指针走到null时,慢指针就到了链表的 倒数第K个节点

    img

所以,所谓快慢指针就是:块指针先走,慢指针待会再走,这样可以不必统计链表的长度

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
var getKthFromEnd = function(head, k) {
    // 定义快慢指针
    let fast = head;
    let slow = head;
    // 快指针先走k步
    while (k > 0) {
        fast = fast.next;
        k--
    }
    // 快慢指针一起走,直到快指针到了null
    while (fast) {
        fast = fast.next;
        slow = slow.next
    }
    // 返回倒数第k个节点
    return slow
};

img