LeetCode-剑指Offer-22-链表中倒数第k个节点


题意描述:

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。


示例:

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

返回链表 4->5.

解题思路:
Alice: 常规的做法是遍历两遍链表,第一遍统计节点个数,然后计算从正面数是第几个节点,然后第二遍遍历输出。
Bob: 也可以使用数组先把所有节点都存下来,然后直接返回,只遍历一遍链表就可以了,不过费内存。
Alice: 还可以考虑双指针,只要两个指针保持 K 个间距,当后面的指针到达链表末尾的 null ,前面的指针就指向了倒数第 K 个节点。
Bob: 我怎么就想不到呢。😢😢
Alice: 不过这道题倒是没有什么边界值之类的测试点。


代码:

Python 方法一:两次遍历

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        cnt  = 0
        node = head
        while node != None:
            node = node.next
            cnt += 1

        bound = cnt - k
        node  = head
        for x in range(bound):
            node = node.next
            
        return node

Python 方法二:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:

        tmp  = []
        node = head
        while node != None:
            tmp.extend([node])
            node = node.next
        
        index = len(tmp) - k
        return tmp[index]  

Python 方法三: 双指针,保持 K 个距离的双指针。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:

        """
        node 和 head 为两个保持了k个间距的指针,当node到达None,head 指向倒数第 K 个节点
        """
        node = head
        for x in range(k):
            node = node.next
        while node != None:
            node = node.next
            head = head.next
        return head
        

Java 方法一: 统计链表元素个数 + 两次遍历

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {

        int cnt = 0;
        ListNode node = head;
        while(node != null){             // 统计链表中元素的总个数
            cnt += 1;
            node = node.next;
        }

        k = cnt - k + 1;                 // 计算需要返回的元素的索引

        node = head;
        for(int i=1; i<k; ++i){          // 返回
            node = node.next;
        }
        return node;
    }
}

Java 方法二: 使用 ArrayList 保存节点。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {

        ArrayList<ListNode> tmp = new ArrayList<ListNode>();
        ListNode node = head;
        while(node != null){
            tmp.add(node);
            node = node.next;
        }
        int index = tmp.size() - k;
        return tmp.get(index);
    }
}

Java 方法三: 双指针。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode node = head;
        for(int i=0; i<k; ++i){
            node = node.next;
        }
        while(node != null){
            node = node.next;
            head = head.next;
        }
        return head;
    }
}

易错点:

  • 一些测试用例:
[1,2,3,4,5]
2
[1,2,3,4,5]
5
[1,2]
2
[1]
1
  • 答案:
[4,5]
[1,2,3,4,5]
[1,2]
[1]

总结:

  • 双指针真是常用啊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值