剑指Offer第5天刷题
今天依旧是链表
链表中环的入口节点
1.判断这个链表有没有环:定义两个引用 fast 和 slow,让它们从这个链表的头结点开始遍历,fast 一次走两步,slow 一次走一步,如果这个链表有环,那么 fast 和 slow 势必会相遇。
2.找到这个链表中环的入口节点:如果这个链表有环,fast 和 slow 在C点相遇,A、B之间的距离是x,B、C之间的距离是y,环的周长为c,那么 fast 走过的路径为 x+c+c-y,slow 走过的路径为 x+c-y。
根据数学的知识:x+c+c-y=2*(x+c-y) 得:x = y
那么让slow重新从A处开始遍历,fast 在C处开始遍历,速度相同,那么 fast和 slow 重新相遇的点就是环的入口节点
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
ListNode fast = pHead;
ListNode slow = pHead;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
break;
}
}
if(fast == null || fast.next == null) return null;
slow = pHead;
while(fast != slow){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
链表中倒数第k个节点
同样的快慢指针,定义 fast 和 slow 遍历链表,先让 fast 走k步,然后让 slow 从头结点开始遍历,fast 一次走一步,slow 一次走一步,等 fast 走到最后一个,slow 的位置就是倒数 k 的位置了,返回 slow 即可。
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
ListNode fast = pHead;
ListNode slow = pHead;
while(k > 0){
if(fast == null){//链表的长度小于k
return null;
}
fast = fast.next;
k--;
}
while(fast != null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
两个链表的第一个公共节点
1.遍历两个链表,分别获得两个链表的长度 len1 和 len2;
2.让长的链表先走len的差值,然后再同时遍历,当a=b时,就找到了第一个公共节点,如果直接走到头,就说明两个链表没有公共节点。
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1 == null || pHead2 == null){
return null;
}
ListNode a = pHead1;
ListNode b = pHead2;
int len1 = 0;
int len2 = 0;
while(a != null){
a = a.next;
len1++;
}
while(b != null){
b = b.next;
len2++;
}
a = pHead1;
b = pHead2;
int len = len1 - len2;
if(len < 0){
a = pHead2;
b = pHead1;
len = len2 - len1;
}
while(len > 0){
a = a.next;
len--;
}
while(a != b){
a = a.next;
b = b.next;
}
if(a == null){
return null;
}
return a;
}
}