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

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

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

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

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


思路1:求出链表的长度

要求的是,倒数k个的链表,那么,需要知道倒数k链表所在的位置,然后定义一个新的头结点,指向倒数第k个结点即可。

倒数第k个,需要找到正数第几个位置?
链表长度 - 倒数第k个 = 正数第几个位置
1,2,3,4,5,6
例如,链表长度为6,倒数第2个(倒数从1开始算,值为5),该位置正数为第4个位置(0开始)
6 - 2 = 4
那么,head从1开始,移动到值为5,需要移动4次

/**
 * 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) {
        //边界值
        if(head == null) return head;
        if(k <= 0) return null;

        //求出head的链表长度
        ListNode tempNode = head;
        int listLength = 0;
        while(tempNode != null){
            tempNode = tempNode.next;
            listLength++;
        }

        if(k > listLength) return head;

        ListNode newHead = head;
        //长度=6,k=2,则当前是6 - 2
        //移动4次
        for(int i = 0; i < listLength - k; i++){
            newHead = newHead.next;
        }
        return newHead;
    }
}

需要对链表遍历两遍:
第一遍找出链表长度
第二遍找出所在结点

那么,能否通过一次遍历解决问题呢?


思路2:双指针

定义两个指针:p1和p2
p1从链表的头部开始遍历向前走k - 1步,p2保持不动;
从第k步开始,两个指针都向前走;
由于两个指针始终相差k - 1步,则当p1走到尾部时,p2指向的位置刚好就是倒数第k个结点的位置,然后返回p2即可。

/**
 * 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) {
        //边界值
        if(head == null) return head;
        if(k <= 0) return null;

        ListNode p1 = head;
        ListNode p2 = head;
        for(int i = 0; i < k - 1; i++){
            p1 = p1.next;
        }

        while(p1.next != null){
            p1 = p1.next;
            p2 = p2.next;
        }

        return p2;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值