链表中倒数第k个结点

11 篇文章 0 订阅
9 篇文章 0 订阅

    牛客网AC地址:http://www.nowcoder.com/books/coding-interviews/529d3ae5a407492994ad2a246518148a?rp=1

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

    题目:输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第一个结点。如一个链表有6个结点,从头结点开始它们的值依次是1、2、3、4、5、6,这个链表的倒数第3个结点是值为4的结点。

    链表的结点定义如下:

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

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

    思路:由单链表的结构可知,单向链表的结点只有从前往后的指针而没有从后往前的指针。

    如果可以遍历链表两次,我们可以第一次遍历链表的时候得到结点的个数n;然后再从头结点开始往后走n-k+1步就可以了。

**但面试官期待的解法只需要遍历链表一次呢?
    我们可以定义两个指针。第一个指针从链表的头指针开始遍历向前走k-1,第二个指针保持不动;
    从第k步开始,第二个指针也开始从链表的头指针开始遍历。
    由于两个指针的距离保持在k-1,当第一个(走在前面的)指针到达链表的尾节点时,第二个指针(走在后面的)指针正好是倒数第k个结点。

    下面是一个例子:在有6个结点的链表上找倒数第3个节点

    根据上述思路可写出代码:

public class Solution {
	public ListNode FindKthToTail(ListNode head, int k) {
		ListNode pre = null;
		ListNode behind = null;

		if (head == null || k <= 0) { // 如果链表为空,或k不满足条件
			return null;
		}
		pre = head;
		for (int i = 0; i < k - 1; i++) {  // 第一个指针向前走k-1步
			if (pre.next != null) {
				pre = pre.next;
			} else { // 结点数目小于k
				return null;
			}
		}
		behind = head;
		while (pre.next != null) {  // 两个指针同时向后走
			pre = pre.next;
			behind = behind.next;
		}
		return behind;
	}
}

    这里需要注意几个边界条件
    1) 链表为空
    2) k没有意义,比如为0,甚至是负数
    3) 链表的长度不足k

    起初一直运行错误,就是因为这几个边界条件考虑得不足,下面是自己第一次AC的代码(思路大致一样,只是定义了很多变量,用于统计两个指针的步数等等):

public class Solution {
	public ListNode FindKthToTail(ListNode head, int k) {
		ListNode kthToTail = null;
		ListNode pre = null;
		ListNode behind = null;

		if (head == null || k <= 0) {
			return null;
		}
		pre = behind = head;
		int temp = 0; // 用于计数
		int length = 0; // 统计链表的长度,对k的最大值进行判断

		while (pre != null) {
			if (pre.next == null) { // 前一个结点到了最后,后一个结点刚好处在倒数k个位置
				kthToTail = behind;
				if (k - 1 > length) {
					return null;
				}
				break;
			}
			if (temp == (k - 1)) { // 前一个指针遍历了(k-1)步,同时移动这两个指针
				pre = pre.next;
				behind = behind.next;
				length++;
			} else {
				pre = pre.next; // 前一个指针先先后遍历
				temp++;
				length++;
			}
		}
		return kthToTail;
	}
}

    最后是测试代码(这里可以多想一些测试用例,多测试几次):

public class Main {
	public static void main(String[] args) {
		ListNode list = null;

		ListNode node_1 = new ListNode(1);
		ListNode node_2 = new ListNode(3);
		ListNode node_3 = new ListNode(5);
		list = node_1;
		list.next = node_2;
		list.next.next = node_3;
		Solution tstSolution = new Solution();
		ListNode kth = tstSolution.FindKthToTail2(list, 2);
		if (kth!=null) {
			System.out.println(kth.val);
		}
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值