剑指offer--算法题--15--链表倒数第k个节点

题目描述:

输入一个链表,输出该链表中倒数第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;
}

结果如下图:


猜你喜欢

转载自blog.csdn.net/lsm18829224913/article/details/80504210