模板(初级,三个模板随着做题的难度来记住。):

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int a = scan.nextInt(); // 读入整数
        double b = scan.nextDouble(); // 读入浮点数
        String s = scan.next(); // 读入字符串(不带空格)
        // ... 你的逻辑
        scan.close(); // 好习惯,关闭扫描器
    }
}


 

中级:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // 1. 创建Scanner对象,固定写法
        Scanner scan = new Scanner(System.in);

        // 2. 读取不同类型的数据
        int n = scan.nextInt(); // 读取一个整数
        long bigNum = scan.nextLong(); // 读取一个长整数(用于大数)
        double d = scan.nextDouble(); // 读取一个双精度浮点数
        float f = scan.nextFloat(); // 读取一个单精度浮点数

        // 3. 读取字符串的几种方式
        String s1 = scan.next(); // 读取一个单词(遇到空格、制表符、换行符就停止)
        String s2 = scan.nextLine(); // 读取一整行(包括空格,直到遇到换行符)
        // 注意:nextLine() 容易和 next()、nextInt() 混用产生问题,需要小心。

        // 4. 判断是否还有下一个输入(在不确定输入数量时有用)
        while (scan.hasNext()) {
            int num = scan.nextInt();
            // ... 处理逻辑
        }

        // 5. 关闭Scanner,释放资源(好习惯)
        scan.close();
    }
}

高级:

import java.util    Scanner;

public class Main {
    public static void main(String[] args) throws IOException {
        // 使用BufferedReader和InputStreamReader,速度更快
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // 读取一行,然后用split分割成字符串数组
        String[] line1 = br.readLine().split(" ");
        int a = Integer.parseInt(line1[0]); // 解析第一个整数
        int b = Integer.parseInt(line1[1]); // 解析第二个整数

        String s = br.readLine(); // 读取一行字符串

        // ... 你的逻辑

        br.close(); // 关闭
    }
}

1.回溯法:

回溯法题目:https://blog.csdn.net/2402_88491560/article/details/154129987?fromshare=blogdetail&sharetype=blogdetail&sharerId=154129987&sharerefer=PC&sharesource=2402_88491560&sharefrom=from_link

1.有递归就有回溯(通常在递归下面部分就是回溯的逻辑)

2.回溯搜索法(纯暴力的搜索):

组合问题:在一个集合里找出大小为某个数字的组合有多少(从 n 个数中选出 k 个,如组合、子集)

切割问题:一个字符串有几种切割方式或加特定条件,如:一个字符串如何切割才能保证它的子串都是回文串。问有几种切割方式。(字符串切割方式)

子集问题(求一个集合的所有子集)

棋盘问题(N 皇后、数独、八皇后等)

3.回溯法的万能模板:

1 void backTracking(参数){
2 if(终止条件){
3     收集结果;
4     return;
5 }
6 for(集合的元素集){
7     处理结点;
8     backTracking(结点);
9     回溯;
10 }
11 }

推荐回溯法观看:https://b23.tv/Tc4sOUD

2.DFS算法

DFS题目和解法:https://blog.csdn.net/2402_88491560/article/details/154127258?fromshare=blogdetail&sharetype=blogdetail&sharerId=154127258&sharerefer=PC&sharesource=2402_88491560&sharefrom=from_link

个人理解:就是一条路走到黑,不撞南墙不回

DFS就像走迷宫的小猫!遇到岔路就选一条走到底,走不通时退回上个路口,继续找能走得通的路

1.把它想象成走迷宫:

你随机选择一个方向一直往前走。

遇到岔路时,随便选一条新路继续走。

如果走到死胡同(碰壁),就退回上一个岔路口,换一条没走过的路再试。

这个过程就是 深度优先——它优先尝试尽可能深入地探索一条路径,直到尽头再回溯。

2.实现:

通常使用 递归 或 栈(Stack) 来实现,因为这符合“先进后出”的回溯需求。

举例:

你要找到家族里所有叫“Tom”的人。

DFS做法:从爷爷开始,先顺着他的大儿子一脉查到底(查大儿子 -> 大儿子的儿子 -> ... 直到最底层),再回溯回来查爷爷的二儿子一脉,以此类推。


1.递归:

递归就是打开一个俄罗斯套娃发现里面还有一个一模一样的、更小的套娃你不断地打开,直到遇到最小的那个(终止条件),然后再一层层地把它套回去。

​关键:必须有终止条件(也叫递归基),否则会无限调用导致栈溢出。

2.栈:

栈 就是你桌上用来放这些套娃的盘子。你每打开一个套娃,就把上半部分放进盘子。你想套回去时,总是从盘子的最上面(最后放进去的)拿起一个盖子。这个盘子就是“栈”。

一种 “后进先出” 的数据结构。

总结:递归是程序表现出的行为,栈是实现这种行为的基础。你可以把递归看作是一种语法糖,它背后是系统在自动为你管理一个调用栈。

​​​​​​3.DFS模板(java模板):

void dfs(参数:当前状态,路径,结果集 ) {
    // 1. 终止条件
    if (结束条件) {
        记录结果/处理答案;
        return;
    }
    
    // 2. 遍历所有选择
    for (所有可能的选择) {
        // 3. 做出选择
        处理当前选择;
        
        // 4. 递归深入
        dfs(新参数);
        
        // 5. 撤销选择(回溯)
        恢复现场;
    }
}

1.有点小技巧:

概念 作用 数据类型 例子(走迷宫)
当前状态 描述"我在哪",是递归函数的核心参数 通常是基本类型:int, (x,y)坐标 当前所在的坐标 (2, 3)
路径 记录"我是怎么来的",是选择序列 列表/数组:存储每一步的选择 路径:["右","右","下"]
结果集 存储"所有找到的解决方案" 列表的列表:存储所有有效路径 结果:[path1, path2, ...]

用"做选择题"的比喻来解释

想象你在做3道选择题(题目1,2,3),每道题有A、B、C三个选项。

三个概念的关系:

路径 = 你已经选的答案序列

比如: [1-A, 2-C]  (第1题选了A,第2题选了C)

状态 = 现在做到哪题了,哪些题还没做

比如: 做到第3题,第1、2题已做完 

结果集 = 所有完整的答题卡

比如: [[1-A,2-B,3-C], [1-A,2-C,3-B], ...] 
 

带入实际例题(java):

题目:给定数字 [1,2,3] ,返回所有可能的排列。

public List<List<Integer>> permute(int[] nums) {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> path = new ArrayList<>();  // 当前路径
    boolean[] used = new boolean[nums.length]; // 标记已使用的元素
    
    dfs(nums, used, path, result);
    return result;
}

private void dfs(int[] nums, boolean[] used, List<Integer> path, List<List<Integer>> result) {
    // 1. 终止条件:路径长度等于数组长度
    if (path.size() == nums.length) {
        result.add(new ArrayList<>(path)); // 注意要new新列表!
        return;
    }
    
    // 2. 遍历所有选择
    for (int i = 0; i < nums.length; i++) {
        // 跳过已使用的元素
        if (used[i]) continue;
        
        // 3. 做出选择
        used[i] = true;
        path.add(nums[i]);
        
        // 4. 递归深入
        dfs(nums, used, path, result);
        
        // 5. 撤销选择(回溯)
        path.remove(path.size() - 1);
        used[i] = false;
    }
}

 推荐DFS算法视频:https://b23.tv/1kSyTSX

看张图放松一下大脑

3.BFS算法:

BFS是一种“地毯式”搜索,由近及远,层层推进。

BFS就是像一群小猫分头找猫饼干。每扇柜门同时闻一闻。

1.想象一下一滴墨水滴入清水中,它总是均匀地向四面八方扩散。

BFS就是这样:

从起点开始。

先访问所有距离为1步的邻居。

再访问所有距离为2步的邻居。

以此类推,直到找到目标或遍历完所有点

这里注意:BFS使用 队列(先进先出) 来保证“由近及远”的顺序。

入队:探索一个新节点时,将其所有未访问的邻居加入队列末尾。

出队:每次从队列头部取出下一个要探索的节点。
 

2.算法步骤

1.将起点放入队列。

从队列中取出一个节点。

检查该节点是否为目标;如果是,搜索结束。

如果不是,将该节点所有未访问的邻居标记为已访问,并加入队列。

重复步骤2-4,直到队列为空或找到目标。

看个结构图:

A - B - C
|   |
D - E
 

A 开始 BFS 的访问顺序是:
A → B → D → C → E

 2.特点:

按层遍历(最短路径可通过 BFS 求得)

需要队列来辅助

时间复杂度:O(V + E)(顶点数 + 边数)

3.其实还可以搞个更简单的例子:

你想认识某生人谢某。

你先问你的直接朋友(第一层),认识谢某吗?

如果不认识,你再让你的每个直接朋友(第一次朋友)去问他们的直接朋友(第二层)。

这样一层层找下去,最早建立联系的那条路径,就是你们之间“关系最短”的路径。

这里记住:BFS找到的路径一定是最短路径。

4.最常用的 二维网格 BFS 模板(比如用于迷宫最短路径、岛屿数量、最短步数等问题)(python)。

from collections import deque

def bfs_grid(grid, start):
    """
    :param grid: 二维网格,例如 [['0','1'], ['1','0']]
    :param start: 起点坐标 (row, col)
    :return: 根据题目需求返回,这里演示计算到所有点的最短步数
    """
    # 网格的行数和列数
    m, n = len(grid), len(grid[0])
    
    # 1. 初始化一个队列,加入起点
    queue = deque()
    queue.append(start)
    
    # 2. 初始化一个 visited 集合或距离矩阵,用于记录已访问/到达该点的步数
    # 方法A(使用集合记录访问过的点): visited = set()
    # visited.add(start)
    
    # 方法B(更常用):使用一个距离矩阵,-1 表示未访问
    dist = [[-1] * n for _ in range(m)]
    r_start, c_start = start
    dist[r_start][c_start] = 0  # 起点到自己的距离为0
    
    # 3. 定义方向向量:代表上下左右四个方向 (dr, dc)
    # 顺序不重要,但必须完整覆盖四个基本方向
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # 右,下,左,上
    # 如果是八连通(含对角线),可添加另外四个方向
    
    # 4. 开始BFS遍历
    while queue:
        # 取出队列最前端的点
        r, c = queue.popleft()
        
        # 如果是终点,可以提前结束(非必须)
        # if (r, c) == target:
        #     break
        
        # 遍历当前点的所有邻居
        for dr, dc in directions:
            # 计算邻居的新坐标
            nr, nc = r + dr, c + dc
            
            # **关键:判断邻居坐标是否合法且可访问**
            # 条件1: 新坐标在网格范围内
            # 条件2: 该格子是可通过的(根据题目,比如不是墙 '1' 或障碍)
            # 条件3: 这个新点没有被访问过 (dist[nr][nc] == -1)
            if (0 <= nr < m and 0 <= nc < n and
                grid[nr][nc] == '0' and  # 假设 '0' 表示可通行的路径
                dist[nr][nc] == -1):
                
                # 标记为已访问,并记录步数
                dist[nr][nc] = dist[r][c] + 1
                # 将这个新点加入队列,以便从它开始继续搜索
                queue.append((nr, nc))
    
    # 返回结果,例如从起点到各点的最短距离矩阵
    return dist


 

模板使用要点:

1.定义“通行条件”:

修改  grid[nr][nc] == '0'  这个条件来匹配你的题目。

示例:

迷宫: grid[nr][nc] == 0  (0代表路,1代表墙)

岛屿问题: grid[nr][nc] == '1'  (1代表陆地,需要遍历)

2.定义“目标”:

如果找特定终点,在  while  循环内添加判断,达到时直接  break  或  return 。

3.记录路径:

如果需要记录路径而不仅仅是距离,可以创建一个  parent  矩阵,在访问邻居时记录  parent[nr][nc] = (r, c) 。

4.初始化:

务必在开始时标记起点为已访问( dist 设为0或加入 visited ),否则可能死循环。
大脑已经燃尽了,看张图放松一下

经典例题对应修改:

1.迷宫最短路径(Leetcode 1926):

通行条件: grid[nr][nc] != '#'  (不是墙)

目标:出口(通常是边界格子)。

2.岛屿数量(Leetcode 200):

通行条件: grid[nr][nc] == '1'  (是陆地)

调用一次BFS会标记整个相连的岛屿为已访问。主函数中遍历所有格子,遇到未访问的陆地就调用BFS,计数+1。

3.腐烂的橘子(Leetcode 994):

初始队列加入所有腐烂橘子的坐标。

通行条件: grid[nr][nc] == 1  (是新鲜橘子)。

5.这里加个BFS的java模板

void bfs(起始点) {
    // 1. 创建队列和visited集合
    Queue<节点类型> queue = new LinkedList<>();
    Set<节点状态> visited = new HashSet<>(); // 或 boolean[][] visited
    
    // 2. 起点入队并标记
    queue.offer(起始点);
    visited.add(起始状态);
    int level = 0; // 记录层数(如果需要)
    
    // 3. BFS循环
    while (!queue.isEmpty()) {
        int size = queue.size(); // 当前层的节点数
        
        // 遍历当前层的所有节点
        for (int i = 0; i < size; i++) {
            // 出队
            节点类型 curr = queue.poll();
            
            // 判断是否到达目标
            if (isTarget(curr)) {
                return level; // 或处理结果
            }
            
            // 遍历所有邻居/下一步选择
            for (节点类型 neighbor : getNeighbors(curr)) {
                // 检查是否访问过
                if (!visited.contains(neighbor状态)) {
                    // 入队并标记
                    queue.offer(neighbor);
                    visited.add(neighbor状态);
                }
            }
        }
        level++; // 层数增加
    }
    
    return -1; // 未找到目标
}

 实战例子:二叉树层序遍历

public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> result = new ArrayList<>();
    if (root == null) return result;
    
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    
    while (!queue.isEmpty()) {
        int levelSize = queue.size();
        List<Integer> levelNodes = new ArrayList<>();
        
        for (int i = 0; i < levelSize; i++) {
            TreeNode node = queue.poll();
            levelNodes.add(node.val);
            
            // 添加左右子节点
            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
        }
        
        result.add(levelNodes);
    }
    
    return result;
}

推荐BFS算法视频:https://b23.tv/VTKY6iJ

4.最短路径

1.问题本质

在地图上找到从A点到B点的最省钱(或最省时间)的走法。

把问题变成日常例子:

想象你要从学校,有好多条路可以走:

小路:近但是堵车(花时间)

大路:远但是畅通(省时间)

高速公路:最快但要交过路费(花钱)

最短路径算法就是帮你算出:哪条路总体“代价”最小?

2.三种算法:

这里有小技巧:

大部分题用Dijkstra- 就像生活中大部分导航都用Dijkstra原理2.

如果题目说“每一步代价一样”,用BFS- 比如走迷宫,求最少步数

如果地点很少但需要查很多次,用Floyd- 比如10个城市之间互相怎么走最近

最简单的心得:

有数字代价 → 想Dijkstra

只数步数 → 想BFS

地点很少 → 想Floyd

1. Dijkstra算法(最常用)→ “保守派找路法”

做法:从家门口开始,一步一步往外探索,每次都先走当前已知的最近的路。

好比:你拿个小本本,先记下从家到小区门口要5分钟,然后发现从小区门口到公交站要3分钟...这样一步步推下去,保证每次扩展的都是当前最近的点。

缺点:如果某条路要收“过路费”(负权值),这个方法会算错。

什么时候用绝大多数情况,因为现实中距离、时间都是正数。

2. Floyd算法 → “上帝视角找路法”

做法:直接把全市所有地点之间的最短距离都算出来,存在一张大表里。

好比:你打开手机地图,它已经提前算好了所有地方之间的最短路径,你问任何两个地方它都能秒答。

缺点:如果城市太大(地点太多),算这张表会非常慢。

什么时候用:当需要反复查询不同地点之间的最短路径时,且城市规模不大。

3. BFS(广度优先搜索)→ “数步数找路法”

做法:不管路的实际长度,只数“转弯次数”或“经过的路口数”。

好比:别人问你怎么走,你说“直走3个路口,左转再走2个路口”,而不关心每个路口之间是多远。

什么时候用:当每条路的“代价”都相同时(比如走格子游戏,每一步代价都是1)。

我知道你眼睛已经疲惫了,放张图休息一下

3.Dijkstra算法(步步为营的探索法)

1.想象一下

你在一个陌生的巨大迷宫里,要从起点走到终点。这个迷宫的特点是:

每条通道的长度不一样

你只能看到当前位置相邻的通道

你的目标是找到总长度最短的路线

Dijkstra的做法就像这样:

从起点开始,拿个小本本记录到每个地方的已知最短距离,每次只走“当前已知最近”的路,走到新地方后,更新这个小本本,重复直到找到终点。

2.举个例子

假设我们要从A点走到E点:

     A
   /     \
 1       3

 /          \
B---2--- C
|            |

4          1
|            |
D---1---E

第一步:初始化

从A出发,A到A的距离是0

其他点暂时记作“无穷远”

已知距离:A(0), B(∞), C(∞), D(∞), E(∞)

第二步:探索最近的邻居

从A出发,有两条路:

A→B:距离1

A→C:距离3

选择最近的B点(距离1),确定A→B的最短距离就是1

第三步:从B点继续探索

从B点可以看到:

B→D:距离4,所以A→B→D = 1+4 = 5

更新已知距离:A(0), B(1), C(3), D(5), E(∞)

第四步:在未确定的点中选最近的

现在未确定的点有:C(3), D(5), E(∞)

选择C点(距离3),确定A→C的最短距离是3

第五步:从C点继续探索

从C点可以看到:

C→E:距离1,所以A→C→E = 3+1 = 4

更新已知距离:A(0), B(1), C(3), D(5), E(4)

第六步:选择下一个最近的点

未确定的点:D(5), E(4)

选择E点(距离4),发现E就是终点,算法结束!

最终结果:最短路径是A→C→E,总距离为4

3.基础模板(邻接表 + 优先队列)java

import java.util.*;

public class DijkstraTemplate {
    
    // 边的定义(可选,用于构建图)
    static class Edge {
        int to;     // 目标节点
        int weight; // 边权
        
        Edge(int to, int weight) {
            this.to = to;
            this.weight = weight;
        }
    }
    
    /**
     * 堆优化Dijkstra算法
     * @param graph 图的邻接表表示,graph[i]包含从节点i出发的所有边
     * @param start 起始节点
     * @return dist数组,dist[i]表示从start到i的最短距离
     */
    public static int[] dijkstra(List<Edge>[] graph, int start) {
        int n = graph.length;
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE); // 初始化为无穷大
        dist[start] = 0;
        
        // 优先队列,按距离从小到大排序
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);
        pq.offer(new int[]{start, 0});
        
        while (!pq.isEmpty()) {
            int[] curr = pq.poll();
            int u = curr[0];      // 当前节点
            int currDist = curr[1]; // 当前距离
            
            // 如果当前距离大于已记录的最短距离,跳过(重要优化)
            if (currDist > dist[u]) {
                continue;
            }
            
            // 遍历所有邻居
            for (Edge edge : graph[u]) {
                int v = edge.to;
                int w = edge.weight;
                int newDist = currDist + w;
                
                // 如果找到更短的路径
                if (newDist < dist[v]) {
                    dist[v] = newDist;
                    pq.offer(new int[]{v, newDist});
                }
            }
        }
        
        return dist;
    }
}

不要急,看图放松

4.网格地图专用模板

import java.util.*;

public class GridDijkstra {
    
    // 四个方向:上、右、下、左
    static int[] dx = {-1, 0, 1, 0};
    static int[] dy = {0, 1, 0, -1};
    
    /**
     * 网格地图的Dijkstra
     * @param grid 网格,grid[i][j]表示该格子的代价
     * @return 从(0,0)到(n-1,m-1)的最短路径和
     */
    public static int dijkstraGrid(int[][] grid) {
        int n = grid.length, m = grid[0].length;
        int[][] dist = new int[n][m];
        
        // 初始化距离矩阵
        for (int i = 0; i < n; i++) {
            Arrays.fill(dist[i], Integer.MAX_VALUE);
        }
        dist[0][0] = grid[0][0];
        
        // 优先队列:[x, y, distance]
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[2] - b[2]);
        pq.offer(new int[]{0, 0, grid[0][0]});
        
        while (!pq.isEmpty()) {
            int[] curr = pq.poll();
            int x = curr[0], y = curr[1], currDist = curr[2];
            
            // 如果当前距离大于已记录距离,跳过
            if (currDist > dist[x][y]) continue;
            
            // 如果是终点,可以直接返回(优化)
            if (x == n-1 && y == m-1) {
                return currDist;
            }
            
            // 遍历四个方向
            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                
                if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
                    int newDist = currDist + grid[nx][ny];
                    if (newDist < dist[nx][ny]) {
                        dist[nx][ny] = newDist;
                        pq.offer(new int[]{nx, ny, newDist});
                    }
                }
            }
        }
        
        return dist[n-1][m-1];
    }
    
    public static void main(String[] args) {
        int[][] grid = {
            {1, 3, 1},
            {1, 5, 1},
            {4, 2, 1}
        };
        
        int result = dijkstraGrid(grid);
        System.out.println("最短路径和: " + result); // 输出: 7
    }
}

推荐Dijkstra视频:https://b23.tv/XwIFpWE

5.java排序算法

https://blog.csdn.net/2402_88491560/article/details/154653648?sharetype=blog&shareId=154653648&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

6.java数组切割:

https://blog.csdn.net/2402_88491560/article/details/154693838?sharetype=blog&shareId=154693838&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

看张照片放松

7.java矩形面积:

https://blog.csdn.net/2402_88491560/article/details/154733532?sharetype=blog&shareId=154733532&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

8.java蜗牛:

https://blog.csdn.net/2402_88491560/article/details/154793305?sharetype=blog&shareId=154793305&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

9.java合并区域:

https://blog.csdn.net/2402_88491560/article/details/154953118?sharetype=blog&shareId=154953118&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

10.java买二赠一:

https://blog.csdn.net/2402_88491560/article/details/154956631?sharetype=blog&shareId=154956631&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

11.java阶乘求和:

https://blog.csdn.net/2402_88491560/article/details/154979571?sharetype=blog&shareId=154979571&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

12.java进制转换:

https://blog.csdn.net/2402_88491560/article/details/155166894?sharetype=blog&shareId=155166894&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

13.java枚举:

https://blog.csdn.net/2402_88491560/article/details/155479576?sharetype=blog&shareId=155479576&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

14.蓝桥javaDP:

https://blog.csdn.net/2402_88491560/article/details/155573088?sharetype=blog&shareId=155573088&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

15.蓝桥java优先排列:

https://blog.csdn.net/2402_88491560/article/details/155644169?fromshare=blogdetail&sharetype=blogdetail&sharerId=155644169&sharerefer=PC&sharesource=2402_88491560&sharefrom=from_link

16.蓝桥java前缀和:

https://blog.csdn.net/2402_88491560/article/details/155908013?sharetype=blog&shareId=155908013&sharerefer=APP&sharesource=2402_88491560&sharefrom=link

17.蓝桥java求最大公约数:

https://blog.csdn.net/2402_88491560/article/details/156946135?fromshare=blogdetail&sharetype=blogdetail&sharerId=156946135&sharerefer=PC&sharesource=2402_88491560&sharefrom=from_link

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐