剑指 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;
}
}