LeetCode刷题
题目
编写一个程序,找到两个单链表相交的起始节点。
例子
解法一暴力法,简单易懂
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 地址相同的第一个点;
ListNode startB = headB;
// 为空的存在
if(headA==null||headB==null){
return null;
}
// 不为空
while(headA!=null){
while(headB!=null){
if(headB==headA){
return headA;
}
headB = headB.next;
}
// 记得回到B的初始点;
headB = startB;
headA = headA.next;
}
return null;
}
解法二利用集合,简单易懂
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set s = new HashSet();
ListNode p = headA;
ListNode q = headB;
//定义一个set之后,不断遍历p链表,然后将所有元素加入到set中
while(p!=null) {
s.add(p);
p = p.next;
}
while(q!=null) {
//遍历q链表,如果q链表的元素出现在set中,
//重合,而这个重合的就是第一个相交的节点就说明
//p和q两个链表有
if(s.contains(q)) {
return q;
}
q = q.next;
}
return null;
}
}
解法三双指针法,有点难度
普通版,用长度差的方法
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = 0, lenB = 0;
// 1.让二者分别走到链表末尾,测出各自长度
ListNode pA = headA;
ListNode pB = headB;
while (pA != null) {
pA = pA.next;
++lenA;
}
while (pB != null) {
pB = pB.next;
++lenB;
}
pA = headA;
pB = headB;
// 2.得到分别链长的差值,让长的先走这个差值
int diff = lenA - lenB;
if (diff > 0) {
int step = diff;
while (step > 0) {
pA = pA.next;
--step;
}
} else if (diff < 0) {
int step = diff;
while (step < 0) {
pB = pB.next;
++step;
}
}
// 3.两指针往前走,相遇即为所求
while (pA != pB) {
pA = pA.next;
pB = pB.next;
}
return pA;
}
大神版
双指针法。初始化两个指针pA和pB分别指向headA和headB,每次pA和pB各走一步,当pA触底后变轨到headB,同理,当pB触底后变轨到headA。这样就只需遍历(A的非公共部分+B的非公共部分+AB的公共部分)。
public ListNode getIntersectionNode_001(ListNode headA, ListNode headB) {
/**
定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部,
最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
**/
if(headA == null || headB == null) return null;
ListNode pA = headA, pB = headB;
// 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头,
// 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null==null
while(pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
完整代码
ListNode
package common;
public class ListNode {
public int val;
public ListNode next;
public ListNode(int x){val = x;}
@Override
public String toString() {
ListNode ss = this;
while(ss!=null) {
String ssss = ss.next==null?"":"->";
System.out.print(ss.val+ssss);
ss = ss.next;
}
System.out.println();
return super.toString();
}
}
Solution
package intersection_of_two_linked_lists;
import common.ListNode;
/**
* 160. 相交链表
* https://leetcode-cn.com/problems/intersection-of-two-linked-lists/description/
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// 地址相同的第一个点;
ListNode startB = headB;
// 为空的存在
if(headA==null||headB==null){
return null;
}
// 不为空
while(headA!=null){
while(headB!=null){
if(headB==headA){
return headA;
}
headB = headB.next;
}
// 记得回到B的初始点;
headB = startB;
headA = headA.next;
}
return null;
}
public static void main(String[] args) {
ListNode l1_001 = new ListNode(4);
ListNode l1_002 = new ListNode(1);
l1_001.next = l1_002;
ListNode l2_001 = new ListNode(5);
ListNode l2_002 = new ListNode(0);
ListNode l2_003 = new ListNode(1);
l2_001.next = l2_002;
l2_002.next = l2_003;
ListNode l3_001 = new ListNode(8);
ListNode l3_002 = new ListNode(4);
ListNode l3_003 = new ListNode(5);
l3_001.next = l3_002;
l3_002.next = l3_003;
l1_002.next = l3_001;
l2_003.next = l3_001;
l1_001.toString();
l2_001.toString();
Solution solu = new Solution();
ListNode l4_001 = solu.getIntersectionNode(l1_001,l2_001);
l4_001.toString();
}
public ListNode getIntersectionNode_001(ListNode headA, ListNode headB) {
/**
定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部,
最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
**/
if(headA == null || headB == null) return null;
ListNode pA = headA, pB = headB;
// 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头,
// 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null==null
while(pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
}
其他
如果只是判断是否存在交点,那么就是另一个问题,即 编程之美 3.6 的问题。有两种解法:
把第一个链表的结尾连接到第二个链表的开头,看第二个链表是否存在环;
或者直接比较两个链表的最后一个节点是否相同。