leetcode链表题汇总(中等难度)

本文深入讲解了多种链表算法,包括两数相加、两两交换节点、删除重复元素等核心问题及其解决思路,提供了丰富的示例和代码实现。

445.用链表表示的两个数相加

题目描述:(情况1
两个非空链表代表两个非负整数,数字最高位是头节点,每个节点存储一位数字,两数相加返回一个和的新链表。可以假设除了0之外,数字都不会以0开头。(这个假设没有实质性作用)
示例:
输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7
特殊示例:(对于进位处理的深度考虑)
输入:5 + 5
输出:1->0

思路分析:
加法从低位开始,即从链表的尾节点往前操作,但是单链表只能从前往后。
从而考虑到利用栈来存放链表中的数字(链表的逆序处理要想到用栈,这点要想到!)
其中while循环的条件注意下!进位操作以及条件注意!
1.定义两个栈并将两个链表放入栈中
2.不断的将两个栈的栈顶相加,注意进位
3.循环条件:任意一个链表不为空 或者 进位c>0

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        
        //由于加法的顺序(从低位开始)与链表的顺序相反,所以需要按逆序处理,则考虑到利用栈进行处理
        Stack<Integer> s1 = new Stack<>();
        Stack<Integer> s2 = new Stack<>();
        while(l1 != null){
            s1.push(l1.val);
            l1 = l1.next;
        }
        while(l2 != null){
            s2.push(l2.val);
            l2 = l2.next; 
        }
        
        //两个栈的栈顶相加(逐个),以及注意进位!
        //注意一种特殊情况,5+5=10,所以再下面的循环判断中需要加一下如果 c>0 时循环继续!!!
        int c = 0;
        ListNode last = null;
        while(!s1.isEmpty() || !s2.isEmpty() || c>0){
            int sum = (s1.isEmpty()?0:s1.pop()) + (s2.isEmpty()?0:s2.pop()) + c;
            c = sum/10;
            ListNode temp = new ListNode(sum%10);
            temp.next = last;
            last = temp; 
        }
        return last; 
    }
}

情况2
反序存放,即链表首部存放个位,这样就可以直接从链表首部开始相加。

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode pre = new ListNode(-1);
        ListNode head = pre;
        int c = 0;//进位
        while(l1 != null || l2 != null || c > 0){
            int add = (l1==null? 0:l1.val) + (l2==null? 0:l2.val) + c;
            c = add / 10;
            int v = add % 10;
            ListNode tmp = new ListNode(v);
            pre.next = tmp;
            pre = tmp;
            if(l1 != null) l1 = l1.next;//如果哪个链表为空了,该链表就不往前走了,持续一直保持空
            if(l2 != null) l2 = l2.next;
        }
        return head.next;
    }
}

24.两两交换链表中的节点

题目描述:
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。>

示例:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
特殊样例分析
[]; [1]; [1,2]; 分别是链表长度为0,1,2的情况;
当0或者1时,提前判断一下;
当长度为2时,由于有一个辅助节点(总长度为3),所以这种情况可跟其余的一起正常考虑。
即进入循环的链表长度需要 >=3(这种情况需要考虑,之前没有考虑到这种长度为2的情况)

思路分析:
首先,链表长度 <= 1时
若链表长度为2时,必须有辅助的第三个节点才能进行改变箭头的操作
错解:交换节点,如果按照交换两个值的那种思想(引入一个temp,交换),这样实际上只是指针在移动,而实际节点没有动,就跟遍历链表时一样只是指针在移动而已
正确做法:改变链表中箭头的方向的思想,画图可直观的增加理解

在这里插入图片描述

class Solution {
    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null) return head;

        //链表长度必须大于2,所以需要再增加一个节点使得两个节点的链表也能交换
        ListNode pre = new ListNode(0);
        pre.next = head;
        head = pre;

        while(pre.next != null && pre.next.next != null){//节点数有奇数和偶数两种,但是对循环条件不影响,由于要往后走两步,所以要确保后面两步分别都要不为空才能移动
            ListNode slow = pre.next;
            ListNode fast = pre.next.next;
            pre.next = fast;
            slow.next = fast.next;
            fast.next = slow;
            pre = slow;
        }
        return head.next;
    }
}

82.删除链表中重复的所有元素

示例:
输入: 1->2->3->3->4->4->5
输出: 1->2->5
输入: 1->1->1->2->3
输出: 2->3
输入:1->1
输出:[]

思路分析:
在这里插入图片描述

class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        
        if(head == null || head.next == null) return head;
        ListNode pre = new ListNode(0);
        pre.next = head;
        head = pre;
       
        while(pre.next != null && pre.next.next != null){
            if(pre.next.val != pre.next.next.val){
               pre = pre.next;
            }
            else{
               ListNode p = pre.next;
               ListNode q = pre.next.next;
               while(p.val == q.val && q.next != null){
                   q = q.next;
               }
               **//以下两个if是上面循环退出的两个原因,需要分别分析做不同的后续处理**
               if(q.next == null){
                   pre.next = null;
               }
               if(p.val != q.val){
                   pre.next = q;
               }
            }
        } 
    return head.next;
    }
}

143.重排链表

示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

思路分析
1.找中间节点(奇数为中间节点,偶数为中间第一个节点)
2.将前半段链表和后半段链表断开(断开时注意把中间节点后面的那个节点,即后半段链表的头节点保存一下)
3. 将后半段链表逆序
4. 将前半段链表和逆序后的后半段链表合并
这个思路很好,但是有可能不容易想到,需要加强

代码中注意的地方:
后半段逆序的时候,while的循环条件
合并两段链表时的while循环条件,只需要是L1 != null && L2 != null
在L1往后面移动时,是L1 = tmp1;而不是L1 = L1.next;(粗心错误陷入死循环,运行超时,因为那条链已经断了)

class Solution {
    public void reorderList(ListNode head) {
        if(head == null) return;

        ListNode midNode = findmidNode(head);//找到中间节点
        ListNode last = recovers(midNode.next);//这就是逆序后的后半段
        midNode.next = null;//则从head,到midNode结束,这位前半段,砍断后面的
        merge(head,last);
    }

    //利用快慢指针寻找中间节点,中间节点的next则为后半段(奇数则为中间节点,偶数则为中间左节点)
    private ListNode findmidNode(ListNode head){
        ListNode fast = head;
        ListNode slow = head;
        while(fast.next != null&& fast.next.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

    //链表逆序
    private ListNode recovers(ListNode head){
        ListNode last = null;
        ListNode pre = head;
        while(pre != null){//循环判断时直接判断该节点是否为空就可,不用判断pre.next,因为循环内指到了pre.next,但是它如果为空,那就直接是pre..next=null,这是可以的。空指针报错的情况应该是用到pre.next,但是pre为空了,这样是不行的。
            ListNode tmp = pre.next;
            pre.next = last;
            last = pre;
            pre = tmp;
        }
        return last;
    }

    //逐个合并两段链表
    private ListNode merge(ListNode L1,ListNode L2){
        ListNode pre = new ListNode(0);
        pre.next = L1;
        ListNode tmp1 = L1;
        ListNode tmp2 = L2;
        while(L1 != null && L2 != null){
            tmp1 = L1.next;
            L1.next = L2;
            //L1 = L1.next;这个会陷入死循环,导致一直是时间按超出限制的错误,这个错误实在是不该犯!!!
            L1 = tmp1;

            tmp2 = L2.next;
            L2.next = L1;
            //L2 = L2.next;
            L2 = tmp2;
        }
    return pre.next;           
    }
}

在这里插入图片描述

链表组件

题目描述:
给定链表头结点 head,该链表上的每个结点都有一个 唯一的整型值 。
同时给定列表 G,该列表是上述链表中整型值的一个子集。
返回列表 G 中组件的个数,这里对组件的定义为:链表中一段最长连续结点的值(该值必须在列表 G 中)构成的集合。

示例 1:
输入:
head: 0->1->2->3
G = [0, 1, 3]
输出: 2
解释: 链表中,0 和 1 是相连接的,且 G 中不包含 2,所以 [0, 1] 是 G 的一个组件,同理 [3] 也是一个组件,故返回 2。
示例 2:
输入:
head: 0->1->2->3->4
G = [0, 3, 1, 4]
输出: 2
解释: 链表中,0 和 1 是相连接的,3 和 4 是相连接的,所以 [0, 1] 和 [3, 4] 是两个组件,故返回 2。

思路分析:
首先利用无序集合set来加速查找速度;(用set加快查找速度很妙!!!)
然后将列表G复制给集合set中;
遍历链表,若当前节点在set中,但是其下一个节点为空或者不在set中的话,说明该节点是一段连续段的末尾,则组件数加1。(这个地方需要反向思维一下,因为一般看到这个题目可能会从列表遍历,去查找链表)

class Solution {
    public int numComponents(ListNode head, int[] G) {
    
    //使用set无序集合来加速查找速度,set的查找速度很快吗
    Set<Integer> set = new HashSet<>();
    //将列表G复制到无序集合中
    for(int x: G){   
        set.add(x);
    }

    //遍历链表,如果当前节点在集合set中,但是下一个节点不在set中或者下一个节点为空,则这个节点是一段组件的末尾,需要组件数加1
    ListNode cur = head;
    int cnt = 0;
    while(cur != null){
        if(set.contains(cur.val) && (cur.next == null || !set.contains(cur.next.val))){
            cnt++;
        }
        cur = cur.next;
    }

    return cnt;
    }
}

02.08 环路检测

题目描述:
给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。

思路分析:
两种思路解析,精妙易懂!

public class Solution {
    public ListNode detectCycle(ListNode head) {
        //快慢指针
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){//当fast走到倒数第二个,其fast.next!=null,进入循环后使得fast=null,再判断时fast.next即空指针了,所以需要保证fast!=null
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                while(slow != head){
                    slow = slow.next;
                    head = head.next;
                }
                return slow;//当再次相遇时即为环的开始点,返回,注意返回的位置
            }
        }    
        return null;//如果没有进入while循环,说明时空链表或者只有一个节点,那么都是无环,返回null。  
    }
}
//执行用时:0 ms, 在所有 Java 提交中击败了100%的用户
//内存消耗:38.3 MB, 在所有 Java 提交中击败了84.10%的用户

/*
public class Solution {
    public ListNode detectCycle(ListNode head) {
        //用哈希表,定义一个set集合,判断链表中的节点是否存在于集合set中
        Set<ListNode> set =  new HashSet<>();
        while(head != null){
            if(!set.add(head)){//如果添加为false,则说明该节点重复出现了
                return head;
            }
            head = head.next;
        }
        return null;
    }
}
//执行用时:4 ms, 在所有 Java 提交中击败了19.10%的用户
//内存消耗:39.7 MB, 在所有 Java 提交中击败了5.61%的用户
*/

725. 分隔链表

题目描述:
将给定的链表分隔成k个连续的部分。每个部分的长度尽可能相等,差距不超过1,且前面部分的长度>=后面部分的长度。这意味着有的部分是为null。
输入:
root = [1, 2, 3], k = 5
输出: [[1],[2],[3],[],[]]
解释:
输入输出各部分都应该是链表,而不是数组。
输入:
root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
输出: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]

思路分析:

  1. 先得需要知道链表的总长度cnt,然后每个部分的平均长度average = cnt / k;
    若 cnt % k != 0的话,需要将余下的节点分别给前面的部分(每个部分只能给1个),即前cnt %k部分的节点数为average+1;后面部分的节点数为average。
  2. 对于后面一些部分为null,这部分的处理。(需要注意!!!)
class Solution {
    public ListNode[] splitListToParts(ListNode root, int k) {

        ListNode cur = root;
        int cnt = 0;
        while(cur != null){
            cnt ++;
            cur = cur.next;
        }

        ListNode pre = cur;//得设置一个pre节点在cur节点前面,以便于断链处理
        cur = root;
        ListNode[] list = new ListNode[k]; //定义一个列表,用来装链表段
        int len = cnt / k;  //平均长度
        int add = cnt % k;  //前add个链表段每个需要额外加一个(因为任意两部分长度差距不超过1;前面的长度>=后面的)

        for(int i = 0;i < k; i++){
            ListNode head = cur;
            for(int j = 0;j < len + (i<add?1:0);j ++){
                if(cur != null){  //要注意不为空时是这样判断,如果是空了得话,直接把head=cur=null给列表就行了
                    pre = cur;
                    cur = cur.next;
                }
            }
            if(cur != null){
                pre.next = null;
            }
           
            list[i] = head; //此处列表,for(i)循环,每段(头节点)装入列表这三个过程很好的思想,需要好好回味!
        }
        return list;
    }
}

1669. 合并链表

题目描述:
在这里插入图片描述

思路分析:
注意:要找到真正的那个节点,但是不要将该节点再另定义为临时节点。指的是就用找到的真实节点指,而不是再定义的临时指针。具体看程序中注释。

class Solution {
    public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) {
        ListNode head = list1;
        ListNode list1B = list1;
        ListNode list1A = list1;
        //先找到list1链表的a-1节点和b+1节点

        int num = 0;
        while(num <= b){
            list1B = list1B.next;
            num ++;
            //if(num == a-1){
                //ListNode tmpA = list1;  //此时list1指在a-1节点,tmpA节点即为a-1节点,这种错误不要再犯了,因为这样只是定义了一个临时节点,它指向别的节点时相当于这个临时节点又跑去指向别的节点了,而不是原来的链断了指向别处了
            //}
        }
        //此时list1B在b+1节点 

        num = 0;
        while(num < a-1){
            list1A = list1A.next;
            num ++;
        }//此时list1A在a-1节点

        //再找到list2链表的头节点和尾节点
        ListNode list2A = list2;
        while(list2A.next != null){
            list2A = list2A.next;
        }//此时list2指在节点m-1


        list1A.next = list2;
        list2A.next = list1B;

        return list1;
    }
}

1171. 从链表中删去总和值为零的连续节点

题目描述:
给你一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。
删除完毕后,请你返回最终结果链表的头节点。
你可以返回任何满足题目要求的答案。
输入:head = [1,2,-3,3,1]
输出:[3,1]
提示:答案 [1,2,1] 也是正确的。

class Solution {
    public ListNode removeZeroSumSublists(ListNode head) {
        //非常精妙的方法,只需要利用哈希表HashMap遍历两遍
        ListNode pre = new ListNode(0);//定义辅助节点0,以更好处理所有节点和为0的情况
        pre.next = head;
        ListNode nodeValue = pre;//nodeValue指将节点作为哈希表的value
        Map<Integer,ListNode> map = new HashMap<>();

        //遍历链表,以建立节点和(key)<-->节点(value)的哈希表
        //当出现相同的和,之前节点value会被覆盖,value更新为当前节点
        int sumKey = 0;//节点和作为哈希表的key
        while(nodeValue != null){
            sumKey += nodeValue.val;
            map.put(sumKey,nodeValue);
            nodeValue = nodeValue.next;
        }

        //第二遍遍历链表求和,并与哈希表进行对比处理
        //若当前节点出的和在下一个节点处出现了,说明两个节点之间的所有节点和为0,直接删除之间的所有节点,若不是,同样与上面的程序语句也可以使得正常指向下一个节点
        nodeValue = pre;
        sumKey = 0;
        while(nodeValue != null){
            sumKey += nodeValue.val;
            nodeValue.next = map.get(sumKey).next;
            nodeValue = nodeValue.next;
        }

        return pre.next;
    }
}
//双指针法
class Solution{
    public ListNode removeZeroSumSublists(ListNode head){
        ListNode pre = new ListNode(0);
        pre.next = head;

        if(head == null) return null;
        if(head.next == null){
            if(head.val == 0) return null;
            else return head;
        }

        ListNode p = pre;
        int sum = 0;
        while(p != null){//p.next
            ListNode q = p.next;
            sum = 0;
            while(q != null){
                sum += q.val;
                if(sum == 0){
                    break;   //如果有多个循环,最内层循环break的话,是跳出最内层循环
                }
                q = q.next;
            }
            //判断内层循环结束的原因并分别处理
            if(sum == 0 && q != null){
                p.next = q.next;
                //p = p.next;
            }
            else{//q==null,说明这一趟没有和为0
                p = p.next;
            }
        }
        return pre.next;
    }
}

19. 删除链表中的倒数第n个节点

//法1:用快慢指针,先让快指针走n步,再快慢指针一起走;当先走的快指针到末尾节点时,慢指针正好到倒数第n个节点的前一个节点(便于删除)。看间隔更容易理解(快慢指针间隔为n)
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode pre = new ListNode(0);//定义虚拟节就可使得头结点不必另外单独处理
        pre.next = head;
        ListNode slow = pre;
        ListNode fast = pre;

        if(head==null || head.next==null) return null;
        while(n > 0){
            fast = fast.next; 
            n--;
        }

        while(fast.next != null){//使slow指在倒数第n个节点的前一个节点,便于删除
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;

        return pre.next;
    }
}

//法2:栈
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        Stack<ListNode> stack = new Stack();
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        head = dummy;
        while(head != null){
            stack.push(head);
            head = head.next;
        }
        for(int i = 0;i < n;i++){
            stack.pop();
        }
        //通过以上出栈,将得到栈定元素为倒数第n个节点的前一个节点,便于删除
        ListNode pre = stack.peek();
        pre.next = pre.next.next;
        return dummy.next;
    }
}

判断环的入口和是否有环

1.判断是否有环

//根据龟兔赛跑原理,快指针一定会追上慢指针,并套了很多圈
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null) return false;//空链表或一个节点链表无环

        ListNode slow = head;
        //ListNode fast = head;
        ListNode fast = head.next;//这个地方fast的初始化需要注意!!!

        while(slow != fast){
            if(fast==null || fast.next==null){
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }
}

2.判断环的入口

//快慢指针法
 //注意点:slow和fast的初始化为啥不在同一节点head?若相同,则一开始slow=fast,那么while循环是先判断再执行,所以while循环就进不去了。
 //可以理解为:有虚拟节点pre,slow从pre开始走了一步到head,fast从pre开始走两步到head.next,这样就相当于是从同一节点出发的,符合龟兔赛跑原理
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null) return head;//空链表或一个节点链表无环

        ListNode slow = head;
        //ListNode fast = head;
        ListNode fast = head.next;//这个地方fast的初始化需要注意!!!

        while(slow != fast){
            if(fast==null || fast.next==null){
                return null;
            }
            slow = slow.next;
            fast = fast.next.next;
        }

        ListNode pre = new ListNode(0);
        pre.next = head;
        while(slow != pre){//按照slow和fast的初始化条件,同一出发点是pre节点,而不是head,若写成head的话,就死循环了!!!
            slow = slow.next;
            pre = pre.next;
        }
        return slow;
    }
}

147.对链表进行插入排序!!!

class Solution {
    public ListNode insertionSortList(ListNode head) {
        if(head == null || head.next == null) return head;
        
        //插入排序
        ListNode dummy = new ListNode(-1);//虚拟节点,便于在头结点之前插入
        dummy.next = head;
        ListNode lastSort = head;//lastSort为有序部分的最后一个节点
        ListNode cur = lastSort.next;//cur为当前待插入节点

        //插入排序处理
        while(cur != null){
            if(lastSort.val <= cur.val){
                lastSort = lastSort.next;
                cur = lastSort.next;
            }
            else{
                lastSort.next = cur.next;//先把cur后的节点保存,免得链断了找不到了
                ListNode prev = dummy;//pre用于在有序部分遍历
                while(prev.next.val <= cur.val){
                    prev = prev.next;
                }

            //插入cur节点
            cur.next = prev.next;//在两个节点之间插入cur,断链重指有顺序要求
            prev.next = cur;
            cur = lastSort.next;
            }
        }
        return dummy.next;
    }
}

86.分隔链表

题目描述:给你一个链表和一个特定值 x ,请你对链表进行分隔,使得所有小于 x 的节点都出现在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。

思路:设置左右虚拟节点,以及左右遍历指针。
对于当前节点,首先保存其后驱节点,再将其从原链中断开连接到左或右链表。因为有断链(即每个当前节点都会从原链中断开),所以每个处理节点在原链表中都是首节点,所以很好处理。

class Solution {
    public ListNode partition(ListNode head, int x) {

        ListNode leftOne = new ListNode(-1);
        ListNode left = leftOne;
        ListNode rightOne = new ListNode(-1);
        ListNode right = rightOne;
        ListNode cur = head;
        if(head == null) return null;

        while(cur != null){
            ListNode next = cur.next;
            if(cur.val < x){
                left.next = cur;
                cur.next = null;//断链,将该节点与链断开;因为每个被处理节点将与链断开,所以每个处理节点都是原来链的头结点
                left = left.next;
            }
            else{
                right.next = cur;
                cur.next = null;
                right = right.next;
            }
            cur = next;
        }

        left.next = rightOne.next;
        right.next = null;

        return leftOne.next;
    }
}

328.奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数

class Solution {
    public ListNode oddEvenList(ListNode head) {
        if(head == null || head.next == null) return head;
        ListNode cur = head;
        ListNode last = cur.next;
        ListNode tmp1 = new ListNode(0);
        tmp1.next = cur;
        ListNode tmp2 = new ListNode(0);
        tmp2.next = last;

        while(cur.next != null && last.next != null){
            cur.next = last.next;
            cur = cur.next;

            last.next = cur.next;
            last = last.next;
        }

        cur.next = tmp2.next;

        return tmp1.next;
    }
}

判断两个链表是否相交并返回交点

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //双指针法
        //走完自己的路,再走对方的路,到交叉点时走了相同距离的路,即相遇,
        //h1+s+h2 = h2+s+h1
        //这道题的思路特别好,主要是一种思路包含了多种情况
        ListNode L1 = headA;
        ListNode L2 = headB;
        while(L1 != L2){
            //L1 = L1.next;
            //L2 = L2.next;
            if(L1 == null)
                L1 = headB;
            else
                L1 = L1.next;
            if(L2 == null)
                L2 = headA;
            else
                L2 = L2.next;
        }
        return L1;
    }
}
*/

//法二:计算两个链表的长度,长的一个先走一部分,再一起从相同的距离走
//这种情况的话,只需要走一遍,若中途有相同节点则有交点,若走到尾相同节点是null,则没有交点。
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode LA = headA;
        ListNode LB = headB;
        int lenA = length(LA);
        int lenB = length(LB);
        int len = 0;

        if(LA == null || LB == null) return null;

        //先走多余长度的那部分
        if(lenA > lenB){
            len = lenA - lenB;
            while(len > 0){
                LA = LA.next;
                len--;
            }
        }
        else if(lenA < lenB){
            len = lenB - lenA;
            while(len > 0){
                LB = LB.next;
                len--;
            }
        }
    
        //从相同的位置开始寻找交点
        while(LA != LB){
            LA = LA.next;
            LB = LB.next;
        }
        return LA;
    }

    //计算链表长度方法,记住另外定义的方法一定要放在原来主方法的外面,类里面
    int length(ListNode head){
        int len = 0;
        while(head != null){  //先指再加
            len++;
            head = head.next;
        }
        return len;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值