剑指offer面试题15 链表中倒数第k个结点

解题思路:

思路1:求链表中倒数第k个节点,也就是正数第n-k+1个结点(假设从1开始计数),此时最直观的做法就是从头开始遍历链表定位到这个第n-k+1个结点即可。但是这种做法需要遍历链表2次,第1次遍历需要求得链表中结点总数,第2次从表头开始找第n-k+1个结点。因此不是最佳解法。

思路2:比较好的做法就是利用双指针,只需遍历链表1次。可以这样考虑,让两个指针p1和p2一开始都指向链表表头,接着让指针p1比p2多走k-1步。然后,p1和p2同时移动,当p1移动至链表末尾时,p2此时正好指向倒数第k个结点处。还需注意一种特殊情况,当k大于链表长度时,即在链表中不存在倒数第k个结点,此时需要单独判断。

public class Solution {

	/**
	 * 常规思路:链表中倒数第k个节点,也就数正数第n-k+1个节点(从1开始计数)
	 * 此时直接从头开始遍历链表定位到这个节点即可,但是这种做法需要遍历节点2次 第1次遍历确定节链表的长度,第2次遍历找到对应节点 
	 * @param head
	 * @param k
	 * @return
	 */
	public ListNode FindKthToTail_simple_idea(ListNode head, int k) {

		// 链表不存在或者k不在合理的范围
		if (head == null || k <= 0) {
			return null;
		}
		// 从头到尾遍历链表,统计链表中节点个数
		int n = 0;
		ListNode p = head;
		while (p != null) {
			n++;
			p = p.next;
		}
		// 此时倒数第k个元素即为正数第n-k+1个
		int target = n - k + 1;
		int index = 1;
		p = head;
		while (index != n - k + 1) {
			index++;
			p = p.next;
		}

		return p;

	}

	class ListNode {
		public int val;
		public ListNode next = null;

		public ListNode(int val) {
			this.val = val;
		}
	}

	/**
	 * 只遍历1次的解法是设置两个指针,因此这道题是一个双指针问题
	 * 先让指针p1比p2多走k-1步,然后两个指针一起走,当指针p1到达链表尾部时,指针p2正好指向 倒数第k-1个
	 * 
	 * @param head
	 * @param k
	 * @return
	 */
	public ListNode FindKthToTail(ListNode head, int k) {

		if (head == null || k <= 0) {
			return null;
		}

		ListNode p1 = head;
		ListNode p2 = head;
		// 首先让p1走k-1步
		// 这里有种特殊情况,如果k大于链表的长度,则p1最终会指向null
		int n = 1;
		while (n != k && p1 != null) {
			n++;
			p1 = p1.next;
		}

		if (p1 != null) {
			//在p1还在链表中的时候
			// 此时p1和p2以同时后移,直到p1到链表的尾节点,
			// 这里有一种特殊情况,若k大于
			while (p1.next != null) {
				p1 = p1.next;
				p2 = p2.next;
			}
			return p2;
		} else {
			return null;
		}


	}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值