【刷穿 LeetCode】剑指 Offer 22. 链表中倒数第k个节点 :「栈/队列」&「差值法」&「快慢指针」

简介: 【刷穿 LeetCode】剑指 Offer 22. 链表中倒数第k个节点 :「栈/队列」&「差值法」&「快慢指针」

网络异常,图片无法展示
|

题目描述



这是 LeetCode 上的 剑指 Offer 22. 链表中倒数第k个节点 ,难度为 简单


Tag : 「链表」、「栈」、「队列」、「快慢指针」


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


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


示例:


给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
复制代码


栈/队列 解法



一个使用额外空间的解法是利用栈(队列),将所有的节点压入占中栈(队列)中,令当前栈(队列)容量为 cntcnt


然后从栈顶(队列头)弹出 kk 个(cnt - k + 1cntk+1 个)元素,最后一个出栈(出队列)的元素即是答案。


网络异常,图片无法展示
|


代码(栈):


class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        Deque<ListNode> d = new ArrayDeque<>();
        while (head != null) {
            d.addLast(head);
            head = head.next;
        }
        ListNode ans = null;
        while (k-- > 0) ans = d.pollLast();
        return ans;
    }
}
复制代码


代码(队列):


class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        Deque<ListNode> d = new ArrayDeque<>();
        while (head != null) {
            d.addLast(head);
            head = head.next;
        }
        k = d.size() - k + 1;
        ListNode ans = null;
        while (k-- > 0) ans = d.pollFirst();
        return ans;
    }
}
复制代码


  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(n)O(n)


差值法



我们可以先对链表进行一次完整遍历,拿到总长度 cntcnt,最后由 cnt - kcntk 即是倒数第 kk 个节点距离 headhead 节点的距离。


网络异常,图片无法展示
|


代码:


class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        int cnt = 0;
        ListNode tmp = head;
        while (tmp != null && ++cnt > 0) tmp = tmp.next;
        cnt -= k;
        while (cnt-- > 0) head = head.next;
        return head; 
    }
}
复制代码


  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)


快慢指针



事实上,我们还可以使用「快慢指针」进行求解。


起始先让快指针 fast 先走 kk 步,此时 fastslow 之间距离为 kk,之后让 fastslow 指针一起走(始终维持相对距离为 kk),当 fast 到达链表尾部,slow 即停在倒数第 kk 个节点处。


网络异常,图片无法展示
|


代码:


class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode slow = head, fast = head;
        while (k-- > 0) fast = fast.next;
        while (fast != null) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}
复制代码


  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)


最后



这是我们「刷穿 LeetCode」系列文章的第 No.剑指 Offer 22. 链表中倒数第k个节点 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。


在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。


为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…


在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

相关文章
链表指针的传参,传值和传地址
本文讨论了链表操作中指针传参的问题,特别是指针的传值与传地址的区别,并提供了修正代码,以确保链表插入操作能正确地修改指针指向的地址。
124 1
链表指针的传参,传值和传地址
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
153 0
LeetCode第二十四题(两两交换链表中的节点)
Leetcode第十九题(删除链表的倒数第N个节点)
LeetCode第19题要求删除链表的倒数第N个节点,可以通过快慢指针法在一次遍历中实现。
198 0
Leetcode第十九题(删除链表的倒数第N个节点)
LeetCode第24题两两交换链表中的节点
这篇文章介绍了LeetCode第24题"两两交换链表中的节点"的解题方法,通过使用虚拟节点和前驱节点技巧,实现了链表中相邻节点的交换。
LeetCode第24题两两交换链表中的节点
【LeetCode 46】450.删除二叉搜索树的节点
【LeetCode 46】450.删除二叉搜索树的节点
166 0
|
存储
一篇文章了解区分指针数组,数组指针,函数指针,链表。
一篇文章了解区分指针数组,数组指针,函数指针,链表。
351 0
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
185 0
|
算法 Python
【Leetcode刷题Python】剑指 Offer 33. 二叉搜索树的后序遍历序列
本文提供了一种Python算法,用以判断给定整数数组是否为某二叉搜索树的后序遍历结果,通过识别根节点并递归验证左右子树的值是否满足二叉搜索树的性质。
130 3
|
存储 算法 数据处理
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表