亡羊补牢,为时不晚;时不我待,舍我其谁!!
链表遗留问题
相交与成环
成环意思是1-2-3-4-5-3-4-5-3-4-5-3……那么3就是入环节点
相交:两个链表有重合部分Y从相交的地方开始后面全都是共同部分,只能是Y不可能是X型因为单链表只有一个指针指向下一个所以不可能出现X相交 以后再分开的情况。
先判断是否成环如果有环返回入环节点:
法一:(用额外空间)
哈希表,从头遍历,检查哈希表中,表中无该节点则加入该节点,cur移动,表中出现某节点时,该节点为入环节点。
法二:(不用额外空间
快慢指针法(记住方法!!)
如果一个链表本身无环,那么最后一个节点一定会指向null。
设定一个快指针(两步),一个慢指针(一步),
如果有环一定会在环上某处相遇,
相遇后快指针从头开始,一次一步,慢指针在原地继续一次一步,再次 相遇时就是在入环节点处!
代码如下:
public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node n1 = head.next; // n1 -> slow
Node n2 = head.next.next; // n2 -> fast
//由于下方while循环,所以初值设置为这样
while (n1 != n2) {
if (n2.next == null || n2.next.next == null) {
return null;
}
n2 = n2.next.next;
n1 = n1.next;
}
n2 = head; // n2 -> walk again from head
while (n1 != n2) {
n1 = n1.next;
n2 = n2.next;
}
return n1;
}
在此基础上,分别调用loop方法分情况
(1)loop1 = = null; loop2 = = null
都没有环,
①此时遍历第一个链表得到end1 len1 == 100
遍历第二个链表得到end2 len2 ==80
②先判断end1和end2是不是同一个地址,
当两个地址不同时,一定不存在相交情况(因为是Y形。如果有相交,至少最后一个节点一定是同一个)
③当两个地址相同时,让长的链表先走完相差的节点数(len1 - len2 = =20),即先走链表1的20个节点,然后链表1和2同时遍历,知道二者第一次相遇,就是要找的第一个相交节点
eg:
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;//这个n用来存放链表1比链表2多出节点的个数(可以为负)
while (cur1.next != null) {
n++;//这样相当于记录了len1
cur1 = cur1.next;
}
while (cur2.next != null) {
n--;//这样相当于直接计算出了len1 - len2 不需要设置len1,2
cur2 = cur2.next;
}
if (cur1 != cur2) {
return null;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;//分别赋值重定位
n = Math.abs(n);
while (n != 0<