- 题目描述:
-
输入一个链表,输出该链表中倒数第k个结点。
(hint: 请务必使用链表。)
- 输入:
-
输入可能包含多个测试样例,输入以EOF结束。
对于每个测试案例,输入的第一行为两个整数n和k(0<=n<=1000, 0<=k<=1000):n代表将要输入的链表元素的个数,k代表要查询倒数第几个的元素。
输入的第二行包括n个数t(1<=t<=1000000):代表链表中的元素。
- 输出:
-
对应每个测试案例,
若有结果,输出相应的查找结果。否则,输出NULL。
- 样例输入:
-
5 2 1 2 3 4 5 1 0 5
- 样例输出:
-
4
NULL
-
例如一个链表有6个结点,从头结点开始它们的值依次是1,2,3,4,5,6.这个链表的倒数第3个结点是值为4的结点
为了得到第K个结点,很自然的想法是先走到链表的尾端,再从尾端回溯K步。可是我们从链表结点的定义可疑看出本题中的链表 是单向链表,单向链表的结点只有从前往后的指针而没有从后往前的指针,因此这种思路行不通。
既然不能从尾节点开始遍历这个链表,我们还是把思路回到头结点上来。假设整个链表有N个结点,那么倒数第K哥结点就是从头结点开始的第n-k-1个结点。如果我们只要从头结点开始往后走n-k+1步就可疑了。如何得到节点数n?这个不难,只需要从头开始遍历链表,没经过一个结点,计数器加1就行了。
也就是说我们需要遍历链表两次,第一次统计出链表中结点的个数,第二次就能找到倒数第k个结点。但是当我们把这个思路解释给面试官之后,他会告诉我们他期待的解法只需要遍历链表一次。
为了实现只遍历链表一次就能找到倒数第k个结点,我们可以定义两个指针。第一个指针从链表的头指针开始遍历向前走k-1。第二个指针保持不动;从第k步开始,第二个指针也开化寺从链表的头指针开始遍历。由于两个指针的距离保持在k-1,当第一个(走在前面的)指针到达链表的尾指结点时,第二个指针正好是倒数第k个结点。
-
package jzoffer; import org.w3c.dom.stylesheets.LinkStyle; public class E15KthNodeFromEnd { public ListNode FindKthToTail(ListNode head,int k){ if(head == null || k<=0){ //先判断特殊情况是否为null,如果为null我们就返回 return null; } ListNode ANode = head;//先建立一个指针A指向头节点 ListNode BNode = null;//再建立一个指针B,先初始化为null,等到A指针移动了k-1一步的时候,我们再让B指针进行相应的移动 for(int i =0;i<k-1;i++){//我们要求倒数k个节点,那么我们就要先让A指针移动k-1步 if(ANode.next != null){ ANode = ANode.next; }else{ return null;//这块主要是判断他是不是至少有k个节点,如果不是那么就直接返回null就好了 } } BNode = head;//上面的A指针已经移动了k-1步了,接下来由B节点从头节点开始移动了,并且是和B节点一块移动的 while(ANode.next != null){//当B节点移动到最后一个节点的话,我们的A节点也应该就移动到我们想要的节点上面了 ANode = ANode.next; BNode = BNode.next; } return BNode; } public static void printList(ListNode listNode){ if(listNode == null){ return; } if(listNode.next == null){ System.out.println(listNode.data); } while(listNode != null){ System.out.print(listNode.data+" "); listNode = listNode.next; } } public static void main(String[] args) { ListNode head = new ListNode(); ListNode second = new ListNode(); ListNode third = new ListNode(); ListNode forth = new ListNode(); ListNode fifth = new ListNode(); ListNode sixth = new ListNode();//创建6个节点 head.next = second; second.next = third; third.next = forth; forth.next = fifth; fifth.next = sixth; sixth.next = null;//将这6个节点按照顺序连接起来 head.data = 1; second.data = 2; third.data = 3; forth.data = 4; fifth.data = 5; sixth.data = 6;//给他们填充数据 E15KthNodeFromEnd test = new E15KthNodeFromEnd(); printList(head); System.out.println(""); System.out.println("我们要求倒数第三个节点的值"); ListNode result = test.FindKthToTail(head, 3); System.out.println("求得倒数第三个节点的值为:"+result.data); } } class ListNode{ int data; ListNode next; }
结果如下图:
-