算法——高频题


用数组结构实现大小固定的队列和栈

队列:先进先出
假设固定大小为len,size为当前队列大小,start表示队头,end表示队尾。

  • 若size<0 或 size>len, 则越界。
  • 出队,end+1位置覆盖一个数。size++; 若end到达数组尾部,则end 返回到数组首部;否则end++
  • 入队,start 位置减去一个数。start–; size–

栈:先进后出
假设固定大小为len, index 表示数组位置

  1. 进栈时,index++ 位置覆盖一个数 index++
  2. 出栈时,index- -
  3. index < 0 或 index >=size ,则越界。

155.最小栈

设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。

  • push(x) – 将元素 x 推入栈中。
  • pop() – 删除栈顶的元素。
  • top() – 获取栈顶元素。
  • getMin() – 检索栈中的最小元素。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

解答:
设计两个栈:data 和 min
data 代表当前栈,min 保存当前栈的最小元素。

进栈时:比较当前元素 x 与 min 栈顶元素 top

  1. 若 x < top, 那么 x 同时进 min 栈
  2. 若 x>=top, 那么数值 top 进 min 栈

出栈时:data 和 min 同时弹出栈顶元素。

mini 的栈顶元素即为 data 栈中的最小元素。

JAVA代码

class MinStack {
    /** initialize your data structure here. */
    private Stack<Integer> stackData;
    private Stack<Integer> stackMin;

    public MinStack() {
        stackData = new Stack<Integer>();
        stackMin = new Stack<Integer>();
    }

    public void push(int x) {
        stackData.push(x);
        if (!stackMin.isEmpty()) {
            if (x < stackMin.peek()) {
                stackMin.push(x);
            }
            else stackMin.push(stackMin.peek());
        }
        else{
            stackMin.push(x);
        }
    }

    public void pop() {
        stackData.pop();

        stackMin.pop();

    }

    public int top() {
        return stackData.peek();
    }

    public int getMin() {
        return stackMin.peek();
    }
}

/**

  • Your MinStack object will be instantiated and called as such:
  • MinStack obj = new MinStack();
  • obj.push(x);
  • obj.pop();
  • int param_3 = obj.top();
  • int param_4 = obj.getMin();
    */

225. 用队列实现栈

使用队列实现栈的下列操作:

扫描二维码关注公众号,回复: 10339494 查看本文章
  • push(x) – 将元素 x 推入栈中。
  • pop() – 删除栈顶的元素。
  • top() – 获取栈顶元素。
  • empty() – 返回栈是否为空

注意:

  • 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
  • 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
  • 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

解答:
用两个队列实现栈结构。
队列:先进先出
栈:先进后出
使用两个队列:data 和 help

出栈:

  1. data 中除最后一个数,其余数依次入队列 help。
  2. data中唯一的一个数出队.
  3. data 和 help地址互换

入栈:直接入队列 data.

JAVA代码:

class MyStack {
    private Queue<Integer> data;
    private Queue<Integer> help;
    /** Initialize your data structure here. */
    public MyStack() {
        data = new LinkedList<Integer>();
        help = new LinkedList<Integer>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        data.add(x);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        while (data.size()>1){
            help.add(data.remove());
        }
        int top = data.remove();
        Queue<Integer> temp = data;
        data = help;
        help = temp;
        return top;
    }
    
    /** Get the top element. */
    public int top() {
        while (data.size()>1){
            help.add(data.remove());
        }
        int top = data.peek();
        help.add(data.remove());
        Queue<Integer> temp = data;
        data = help;
        help = temp;
        return top;
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        if (data.isEmpty()){
            return true;
        }
        else return false;
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

232. 用栈实现队列

使用栈实现队列的下列操作:

  • push(x) – 将一个元素放入队列的尾部。
  • pop() – 从队列首部移除元素。
  • peek() – 返回队列首部的元素。
  • empty() – 返回队列是否为空。

示例:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);  
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false

说明:

  • 你只能使用标准的栈操作 – 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。

解答:
用两个栈结构:push 和 pop

  • 入队:进 push 栈
  • 出队:
    若 pop 为空,push 栈里面的数依次倒进 pop, pop栈顶弹出
    若 pop 不为空,那么push中的元素要全部倒进pop, pop栈顶弹出

JAVA代码:

class MyQueue {
    private Stack<Integer> push;
    private Stack<Integer> pop;

    /** Initialize your data structure here. */
    public MyQueue() {
        push = new Stack<Integer>();
        pop = new Stack<Integer>();
    }
    
    /** Push element x to the back of queue. */
    public void push(int x) {
        push.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        if (pop.empty()){
            while (!push.empty()){
                pop.push(push.pop());
            }
        }
        return pop.pop();
    }
    
    /** Get the front element. */
    public int peek() {
        if (pop.empty()){
            while (!push.empty()){
                pop.push(push.pop());
            }
        }
        return pop.peek();
    }
    
    /** Returns whether the queue is empty. */
    public boolean empty() {
        if (push.empty() && pop.empty()){
            return true;
        }
        else return false;
    }
}

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * boolean param_4 = obj.empty();
 */

猫狗队列


59. 螺旋矩阵 II

给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

示例:

输入: 3
输出:
[
 [ 1, 2, 3 ],
 [ 8, 9, 4 ],
 [ 7, 6, 5 ]
]

题解:
T,B,L,R分别表示未扫描矩阵的边界。
初始时,T=0,B=n-1,L=0,R=n-1; 直到整个矩阵扫完完毕结束。
先从左到右行扫描,第T行的第L列到第R列,即nums[T][L]~nums[T][R];扫描完一行,相应T增1.
从上到下列扫描,第R列的第T行到第B行,即nums[T][R]~nums[B][R];扫描完一列,相应R减1.
从右到左行扫描,第B行的第R列到第L列,即nums[B][R]~nums[B][L];扫描完一行,相应B减1.
从下到上列扫描,第L列的第B行到第T行,即nums[B][L]~nums[T][L];扫描完一列,相应L增1.
在这里插入图片描述


JAVA代码:

class Solution {
    public int[][] generateMatrix(int n) {
        
        /*
        从左到右一行
        从上到下一列
        从右到左一行
        从下到上一列
        */
        int[][] res = new int[n][n];
        int num = 1;
        int l = 0;
        int r= n-1;
        int t = 0;
        int b = n-1;
        int i=0;
        while(num<=n*n){
        //从左到右
        for (i=l; i<=r; i++) res[t][i] = num++; 
        t++;
        //从上到下
        for (i=t; i<=b; i++) res[i][r] = num++;
        r--;
        //从右到左
        for (i=r; i>=l; i--) res[b][i] = num++;
        b--;
        //从下到上
        for (i=b; i>=t; i--) res[i][l] = num++;
        l++;
        }
     return res; 
    }

}

面试题 01.07. 旋转矩阵

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-matrix-lcci

给定一幅由N × N矩阵表示的图像,其中每个像素的大小为4字节,编写一种方法,将图像旋转90度。
不占用额外内存空间能否做到?

示例 1:

给定 matrix = 
[
  [1,2,3],
  [4,5,6],
  [7,8,9]
],

原地旋转输入矩阵,使其变为:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

示例 2:

给定 matrix =
[
  [ 5, 1, 9,11],
  [ 2, 4, 8,10],
  [13, 3, 6, 7],
  [15,14,12,16]
], 

原地旋转输入矩阵,使其变为:
[
  [15,13, 2, 5],
  [14, 3, 4, 1],
  [12, 6, 8, 9],
  [16, 7,10,11]
]

第 i 行与第 n-i-1 列对应元素交换,而后上下翻转.
解答:
在这里插入图片描述
JAVA代码

class Solution {
    public void rotate(int[][] matrix) {
        //先交换
        int size = matrix.length;
        for (int i=0; i<size; i++){
            for (int j=0; j<size-i-1; j++){
                matrix[i][j] = matrix[i][j]^matrix[size-j-1][size-i-1];
                matrix[size-j-1][size-i-1] = matrix[i][j]^matrix[size-j-1][size-i-1];
                 matrix[i][j] = matrix[i][j]^matrix[size-j-1][size-i-1];
            }
        }
        
        //再上下翻转
        for (int i=0; i<size/2; i++){
            for (int j=0; j<size; j++){
                matrix[i][j] = matrix[i][j]^matrix[size-i-1][j];
                matrix[size-i-1][j] = matrix[i][j]^matrix[size-i-1][j];
                matrix[i][j] = matrix[i][j]^matrix[size-i-1][j];
            }
        }
    }
}

206. 反转链表

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list

反转一个单链表。
示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

解答:
迭代版

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode curr = head;
        ListNode prev = null;
        ListNode temp = null;
        
        while (curr!=null){
            temp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = temp;
        }
        return prev;
    }
}

递归版

class Solution {
    public ListNode reverseList(ListNode head) {
        if (head==null || head.next==null){
            return head;
        }
        ListNode res = reverseList(head.next); //反转链表head.next
        //最后将head反转
        head.next.next = head;
        head.next = null;
        return res;
    }
}

翻转双向链表


498. 对角线遍历

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/diagonal-traverse
给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。

示例:

输入:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]

输出:  [1,2,4,7,5,3,6,8,9]

解释:
在这里插入图片描述
说明:
给定矩阵中的元素总数不会超过 100000 。

题解:
设计宏观结构:
设置A表示右上的位置,B表示左下的位置。
每次,设置A往右走一步,到最右了再往下走;同时B往下走,到最下了再往右走;
扫描从左下B走到右上A的元素,或者从右上A走到左下B的元素。
当A和B同时走到最后一个元素位置时遍历结束。
JAVA代码

class Solution {
    public int[] findDiagonalOrder(int[][] matrix) {
        //判空
         if (matrix == null || matrix.length == 0) {
            return new int[0];
        }

        //矩阵M行,N列
        int M = matrix.length;
        int N = matrix[0].length;
            
        int[] res = new int[M*N];
        
        //点A:matrix[aRow][aCol], 点B: matrix[bRow][bRow]
        int aRow = 0;
        int aCol = 0;
        int bRow = 0;
        int bCol = 0;
        
        res[0] = matrix[0][0]; //先把第一个元素装进去
        int k = 1;  //k为res的下标
        int flag = 1;  //立个flag,当flag为奇数: A->B; 当flag为偶数:B->A
        while (aRow < M && bRow < M && aCol < N && bCol < N){
            //A每次往右走一步,到最右再往下走
            //B每次往下走一步,到最下再往右走
            aRow = aCol == N-1? aRow+1: aRow;
            aCol = aCol < N-1? aCol+1: aCol;
            bCol = bRow == M-1? bCol+1: bCol;
            bRow = bRow < M-1? bRow+1: bRow;
            
            //从左下B向右上A方向扫描
            //或从右上A向左下B方向扫描
            // A->B
            if (flag %2 == 1){
                int i = aRow;
                int j = aCol;
                while (i<=bRow && j>=bCol){
                    res[k++] = matrix[i++][j--];
                }
                flag++;
            }
            // B->A
            else if(flag%2 == 0){
                int i = bRow;
                int j = bCol;
                while (i>=aRow && j<=aCol){
                    res[k++] = matrix[i--][j++];
                    
                }
                flag++;
            }
        }
        return res;
    }
       
}

在行列都排好序的矩阵中找数

【题目】 给定一个有N*M的整型矩阵matrix和一个整数K, matrix的每一行和每一 列都是排好序的。实现一个函数,判断K 是否在matrix中。 例如: 0 1 2 5 2 3 4 7 4 4 4 8 5 7 7 9 如果K为7,返回true;如果K为6,返 回false。 【要求】 时间复杂度为O(N+M),额外空间复杂度为O(1)。

解答
从后向前找。


找两个链表的公共部分

【题目】: 给定两个有序链表的头指针head1,和head2,打印两个链表的公共部分.
和归并排序中merge过程类似


234. 回文链表

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-linked-list
请判断一个链表是否为回文链表。
示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true

进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
解答:
思路一:
考虑到栈结构出栈时是逆序的,因此借助栈。
扫描一遍链表,并将数值存放到栈中;
再扫描一遍链表,每扫描一个结点查看是否与栈顶元素相等,并弹出一个元素。若每次都相等,则是回文链表。
空间复杂度O(n)

思路二:
链表后半段入栈,并将链表前半段与栈比较。
(找中点的方式,快指针一次走两步,慢指针一次走一步)
空间复杂度O(n/2)

思路三:
链表后半段逆序,比较两个链表是否相等。
链表后半段再次还原回来。
注意的地方:
首先不管链表结点个数是奇数个还是偶数个,后部分头结点都是p1后一个结点,因此p1确定了,后半部分就确定了。
其次当链表结点为奇数个时,那么前半部分链表长度比后半部分多1,但在比对时,不用考虑前半部分最后一个结点,只要后半部分链表指针到了结尾,那么就算比对成功。

时间复杂度O(n+n/2) = O(n);
只用到了常数个指针,因此空间复杂度为O(1).
在这里插入图片描述
JAVA代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        //定义一个快指针和一个慢指针
        ListNode p1 = head;
        ListNode p2 = head;
        if (head == null || head.next == null) return true;
        //找到中点,p1指向中点, p2指向中点的后面一个结点
        while(p2.next!=null && p2.next.next!=null){
            p1 = p1.next;
            p2 = p2.next.next;
        }
        p2 = p1.next;
        p1.next = null;
        
        //反转链表后半部分,rev为反转后的链表
        ListNode p3 = null;
        while (p2!=null){
            ListNode temp = p2.next;
            p2.next = p3;
            p3 = p2;
            p2 = temp;
        }
        ListNode rev = p3;
        
        //比较两个链表
        p1 = head;
        while(p3!=null){
            if ( p1.val == p3.val){
                p1 = p1.next;
                p3 = p3.next;
            }
            else break;
        }
        if (p3 == null){
            return true;
        }else{
            return false;
        }
    }
}

将单向链表按某值划分成左边小、 中间相等、 右边大的形式

【题目】:
给定一个单项链表的头结点head,节点的值类型时整形,再给定一个整数pivot。实现一个调整链表的函数,左半部分小于pivot,中间部分等于,右半部分大于。但是对于调整后的节点顺序没有更多的要求。
例如:
9->0->4->5->1,pivot=3
结果可以为1->0->4->9->5,也可以为0->1->9->5->4


上一题进阶: 在原问题的要求之上再增加如下两个要求。

在左、中、右三个部分的内部也做顺序要求,要求每部分里的节点从左到右的顺序与原链表中节点的先后次序一致。
例如:链表9->0->4->5->1,pivot=3。
调整后的链表是0->1->9->4->5。
在满足原问题要求的同时,左部分节点从左到右为0、1。在原链表中也 是先出现0,后出现1;中间部分在本例中为空,不再讨论;
右部分节点 从左到右为9、4、5。在原链表中也是先出现9,然后出现4,最后出现5。
如果链表长度为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1)。
解答:
定义三个结点less、equal、more
遍历链表:
当前结点值小于num,则将结点接在less后面
当前结点值等于num,则将结点接在equal后面
当前结点等于num,则将结点接在more后面
最后将less、equal 和 more 拼接.


138. 复制带随机指针的链表

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。

示例 :

在这里插入图片描述

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]

提示:

-10000 <= Node.val <= 10000
Node.random 为空(null)或指向链表中的节点。
节点数目不超过 1000 。

解答:
将每个拷贝节点都作为原来节点下一个结点。
新节点的随机指针指向 原结点随机指针指向的结点的下一个结点。
最后将原结点删除。

在这里插入图片描述

JAVA代码

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        //判空
        if (head == null) return null;
        
        //复制结点插入原链表
        Node p = head;
        while(p!=null){
            Node copyP = new Node(p.val);
            copyP.next = p.next;
            p.next = copyP;
            p = copyP.next;
        }
        
        //复制节点加上random指针
        p = head;
        Node copyP = head.next;
        while (p!=null){  //原链表某结点的random指向为空,则复制结点的random结点也指向空
            p.next.random = p.random!=null? p.random.next: null;
            p = p.next.next;
        }
        
        //调整next指针
        p = head;
        Node headCopy = head.next;
        copyP = headCopy;
        
        while (copyP.next != null){
            p.next = copyP.next;
            p = copyP.next;
            copyP.next = p.next;
            copyP = p.next;
        }
        p.next = null;
        return headCopy;
        
    }
}

两个单链表相交的一系列问题

【题目】:
单链表可能有环,也可能无环。给定两个单链表的头节点head1和head2,这两个链表可能相交,也可能不相交。请实现一个函数,如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null。
要求:
如果链表1的长度为N,链表2的长度为M,时间复杂度请达到O(N+M),额外空间复杂度请达到O(1)。

【问题一】判断链表是否有环

141. 环形链表

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle

给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

解答:

  1. 思路一:
    哈希表
    将结点放入哈希表,看当前结点是否已存在于哈希表中,若存在则有环。
    第一个在哈希表中存在的结点为 环入口。
    JAVA代码
//哈希表法
public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode p = head;
        Set<ListNode> nodes = new HashSet<>();
        while(p!=null){
            if (nodes.contains(p)){
                return true;
            }
            else {
                nodes.add(p);
            }
            p = p.next;
        }
        return false;
    }
}
  1. 思路二:
    准备两个指针F 和 S。
    F: 快指针,一次走两步
    S: 慢指针,一次走一步
    若无环,快指针会一直走到空结点。
    若有环,则快指针和慢指针一定会相遇;相遇后,将F指向头指针,之后F和S每次走一步,再次相遇的结点则为 环入口。

JAVA代码

public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;
        ListNode fast = head.next;
        ListNode slow = head;
        while(fast!=slow){
            if (fast == null || fast.next==null){
                return false;
            }
            fast = fast.next.next;
            slow = slow.next;
        }
        return true;  
    }
}

【问题二】无环链表相交

面试题 02.07. 链表相交
  1. 思路一
    哈希表法:
    首先链表1入哈希表,然后遍历哈希表2,若当前结点存在于哈希表中,则表示相交,并且该节点为相交节点.

JAVA代码

//哈希表法
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        Set<ListNode> nodes = new HashSet<>();
        
        //链表A节点装进哈希表
        ListNode currA = headA;
        while (currA!=null){
            nodes.add(currA);
            currA = currA.next;
        }
        
        //查看链表B节点在哈希表中是否存在
        ListNode currB = headB;
        while (currB!=null){
            if (nodes.contains(currB)){
                return currB;
            }
            currB = currB.next;
        }
        return null;
    }
}
  1. 思路二
    首先遍历链表1,统计链表1的长度 len1,以及获取链表1的最后一个节点 end1.
    然后遍历链表2,统计链表2的长度 len2,以及获取链表2的最后一个节点 end2.
    判断 end1 是否等于 end2(内存地址),若不相等,则两个链表不可能相交。

若相等,则两个链表相交,(但最后一个节点不一定是第一个相交的节点)。
最后较长的长链表从头开始走|len1-len2|步。此时剩余长度与短链表长度相等;
短链表从头与长链表剩余部分同步向后走,一定会走到两个链表相交的节点处。
在这里插入图片描述
JAVA代码

//双指针法
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //判空
        if (headA==null || headB==null) return null;
        
        //遍历表A, 统计长度并获得最后一个节点
        int lenA = 0;
        ListNode currA = headA;
        while (currA.next!=null){
            lenA++;
            currA = currA.next;
        }
        lenA++;
        
        //遍历表B, 统计长度并获得最后一个节点
        int lenB = 0;
        ListNode currB = headB;
        while (currB.next!=null){
            lenB++;
            currB = currB.next;
        }
        lenB++;
        
        //若有交点,最后一个节点相等
        if (currA==currB){
            //使A为长链表
            if (lenA<lenB){
                ListNode temp = headA;
                headA = headB;
                headB = temp;
            }
            int len = Math.abs(lenA-lenB);
            
            //长链表先走len步
            currA = headA;
            for (int i = len; i>0; i--){
                currA = currA.next;
            }
            
            currB = headB;
            //两个链表同步向后走
            while(currA!=currB){
                currA = currA.next;
                currB = currB.next;
            }
            return currA;
            
        }
        return null;
    }
}

【问题三】有环链表相交
解答:
只存在三种情形的拓扑结构,如图。
在这里插入图片描述
首先找到两个链表各自的入环点 loop1 和 loop2。

  1. loop1 == loop2 时,则为第 (2) 种情况,此时只要按照与无环链表相同的方法找相交点。
  2. loop1 != loop2 时,为第 (1) 或第 (3) 种情况。
    此时再以 loop1 为起点一直向后找:
    若最先找到 loop1,则为第(1)种情况,无交点。
    若最先找到 loop2, 则为第 (3) 种情况,交点为 loop1 或 loop2.
发布了9 篇原创文章 · 获赞 0 · 访问量 253

猜你喜欢

转载自blog.csdn.net/powerful_ren/article/details/104870141
今日推荐