【面试题15】链表中倒数第k个结点
【题目描述】
输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第一个结点。
例如,一个链表有6个结点,从头结点开始他们的值依次是1,2,3,4,5,6。
这个链表的都属第三个结点是值为4的结点。
【解决方案】
方法:设置两个指针p1,p2。p1先走k个结点,然后p2开始和p1同步走,p1走到尾结点的时候,p2所指的结点即为倒数第k个结点。
考虑特殊情况:
1. 链表为空;
2. 链表结点数量小于k;
3. 输入k小于等于0的情况,会影响程序的鲁棒性(具体看代码);
我的代码实现,仅供参考:
1 public static ListNode FindKthNode(ListNode head, int k) 2 { 3 if (head == null || k<=0) 4 { 5 return null; 6 } 7 8 ListNode p1 = head , p2 = head; 9 10 //根据题意链表尾节点为倒数第一个 11 //故i < k-1,所以k > 0 12 for (int i = 0; i < k-1; i++) 13 { 14 //处理链表结点数量小于k的情况 15 if (p1.Next == null) 16 { 17 return null; 18 } 19 else 20 { 21 p1 = p1.Next; 22 } 23 } 24 25 while (p1.Next != null) 26 { 27 p1 = p1.Next; 28 p2 = p2.Next; 29 } 30 31 return p2; 32 }
【相关题目】
1. 求链表的中间结点。如果链表中结点总数为奇数,则返回中间结点,如果为偶数,则返回中间结点两个中的任意一个。
方法:设置两个指针p1,p2。同时从head开始走,p1每次走两步,p2每次走一步,p1到达尾节点时,p2所指结点即为中间结点。
我的代码实现,仅供参考:
1 public static ListNode FindMidhNode(ListNode head) 2 { 3 if (head == null) 4 { 5 return null; 6 } 7 8 ListNode p1 = head, p2 = head; 9 10 while (p1.Next!=null && p1.Next.Next != null) 11 { 12 p1 = p1.Next.Next; 13 p2 = p2.Next; 14 } 15 16 return p2; 17 }
2. 判断一个单向链表是否形成了环形结构。
方法:设置两个指针p1,p2。同时出发,p1每次走两步,p2每次走一步,如果p1追上p2,和p2所指结点相同,则证明链表中存在环形结构。
我的代码实现,仅供参考:
1 public static bool HasCircle(ListNode head) 2 { 3 if (head == null || head.Next == null) 4 { 5 return false; 6 } 7 8 ListNode p1 = head.Next, p2 = head; 9 bool hasCircle = false; 10 11 while (p1.Next != null && p1.Next.Next != null) 12 { 13 if (p1 == p2) 14 { 15 hasCircle = true; 16 break; 17 } 18 p1 = p1.Next.Next; 19 p2 = p2.Next; 20 } 21 22 return hasCircle; 23 }
【举一反三】
当我们用一个指针遍历链表不能解决问题的时候,可以尝试用两个指针来遍历链表。可以让其中一个指针遍历的速度快一些,或者让它先在链表上走若干步。