《剑指Offer》第二版之链表中倒数第k个节点(十)

目录


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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章