目录
题目:
输入一个链表,输出该链表中倒数第k个节点,为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第一个节点。例如,一个链表有6个节点,从头节点开始,他们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。链表节点定义如下:struct ListNode
{
int m_nValue;
ListNode m_pNext;
}
思路:
假设整个链表有n个节点,那么倒数第k个节点就是从头节点开始的第n-k+1个节点。如果我们能够得到链表中节点的个数n,那么只要从头节点开始往后走n-k+1步就可以了。如何得到节点n?这个不难,只需要从头节点开始遍历链表,每经过一个节点,计数器加1就可以了。也就是说我们需要遍历链表两次,第一次统计出链表中节点的个数,第二次就能找到倒数第k个节点。但是当我们把这种思路解释给面试官之后,他会告诉我们他期待的解法只需要遍历链表一次。
为了实现只遍历链表一次就能找到倒数第k个节点,我们可以定义两个指针。第一个指针从链表的头指针开始遍历向前走k-1步,第二个指针保持不动;从第k步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在k-1,当第一个(走在最前面)指针到达链表的尾节点时,第二个(走在最后面)指针正好指向倒数第k个节点。
步骤
1.首先用第一个指针从头节点开始向前走两(2=3-1)步到达第3个节点。 2.接着把第二个指针初始化指向链表的第一个节点。 3.最后让两个指针同时向前遍历,当第一个指针到达链表的尾节点时,第二个指针指向的刚好就是倒数第3个节点。代码:
package test;
public class FindKthToTail {
public static void main(String[] args) {
ListNode ln1 = new ListNode();
ListNode ln2 = new ListNode();
ListNode ln3 = new ListNode();
ListNode ln4 = new ListNode();
ListNode ln5 = new ListNode();
ListNode ln6 = new ListNode();
ln1.value = 1;
ln1.next = ln2;
ln2.value = 2;
ln2.next = ln3;
ln3.value = 3;
ln3.next = ln4;
ln4.value = 4;
ln4.next = ln5;
ln5.value = 5;
ln5.next = ln6;
ln6.value = 6;
ln6.next = null;
System.out.println(findKthToTail(ln1, 3).value);
}
public static ListNode findKthToTail(ListNode pListHead, int k) {
//1.校验数据的合法性
if(pListHead == null || k == 0) {
return null;
}
ListNode pAhead = pListHead;
ListNode pBehind = null;
//2.将p1指针移动k-1个位置
for (int i = 0; i < k - 1; i++) {
if(pAhead.next != null)
pAhead = pAhead.next;
else
return null;
}
//3.将p2指针从头节点开始移动直到p1指针到达尾节点
pBehind = pListHead;
while(pAhead.next != null) {
pAhead = pAhead.next;
pBehind = pBehind.next;
}
return pBehind;
}
static class ListNode {
int value;
ListNode next;
}
}