LeetCode之回溯算法

文章目录

  • 思想&框架
    • 1.组合/子集和排列问题
    • 2.组合应用问题
  • 组合/子集问题
    • 1. lc77 组合
    • 2. lc216 组合总和III
    • 3. lc39 组合总和
    • 4. lc40 组合总和II
    • 5. lc78 子集
    • 6. lc90 子集II
  • 排列
    • 1. 全排列I
    • 2. 全排列II
  • 组合问题的应用
    • 1.lc17 电话号码的字母组合
    • 2.lc131 分割回文串
    • 3. lc19 复原IP地址
  • 岛屿问题&棋盘问题

思想&框架

首先统一的框架是:

result = []
def dfs(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return
    
    for 选择 in 选择列表:
        做选择
       dfs(路径, 选择列表)
        撤销选择

其实就是把回溯问题看成一个多叉树,for循环去遍历树的宽度,dfs回溯去深度遍历

主要有这么几类问题:组合/子集和排列,岛屿问题,分割问题,棋盘问题

1.组合/子集和排列问题

第一个大类就是组合/子集和排列问题,围绕着元素重不重复,可不可以复选
基本技巧就是:
组合/ 子集:startIndex
排列:used数组&排序

具体点的关键代码(来点投机取巧速记的)
组合/子集

  • 元素不重复且不可重复选:dfs(n,k,i+1)
  • 元素不重复且可重复选:dfs(n,k,i)
  • 元素重复且不可重复选:排序 & nums[i]==nums[i-1]判断

排列

  • 元素不重复:used数组,
  • 元素重复:排序+nums[i]==nums[i-1]判断+used数组

2.组合应用问题

需要灵活运用,不单单是上面几种的变种,更多的是回溯思维的提升

组合/子集问题

子集和组合问题基本一致,唯一不同就是子集收集的是树的所有节点,而组合收集的是叶子节点。

1. lc77 组合

力扣链接

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合
输入:n = 4, k = 2
输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4],]

Solution
(记住下面这个基本的板子!)

    // 两个全局变量(也可以放进递归的参数中)
    List<List<Integer>> list = new ArrayList<>(); // 存放结果集
    LinkedList<Integer> path = new LinkedList<>();  // 存放每次的结果
     
    public  List<List<Integer>> combine(int n, int k) {
        backTracking(n,k,1);
        return list;
    }

    public void  backTracking(int n,int k,int startIndex)
    {
        if(path.size()==k)
        {
            // 注意这里要新建ArrayList的path
            list.add(new ArrayList<>(path));
            return;
        }
        //for(int i=startIndex;i<=n;i++),i<=n-(k-path.size())+1 是剪枝操作
        for(int i=startIndex;i<=n-(k-path.size())+1;i++)
        {
            path.add(i);
            backTracking(n,k,i+1);
            path.removeLast();
        }
    }

两个细节:
(1) 一个是list.add(new ArrayList<>(path));,为什么不能直接add(path)?
因为变量 path 所指向的列表 在深度优先遍历的过程中只有一份 ,深度优先遍历完成以后,回到了根结点,成为空列表。
在 Java 中,参数传递是 值传递,对象类型变量在传参的过程中,复制的是变量的地址。这些地址被添加到 res 变量,但实际上指向的是同一块内存地址,因此我们会看到 66 个空的列表对象。解决的方法很简单,在 res.add(path); 这里做一次拷贝即可。
(链接:https://leetcode.cn/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/)

(2) 另一个就是剪枝,怎么判断剪枝条件?
可以这么想,i是有搜索上界的,i越大,剩下可选的数就越少,这样就不满足k的要求,也就没必要再搜索下去。
要组成大小为k的path,此时还需要k - path.size()个数,如果[i, n]这个区间内,(有n - i + 1个数)不足这么多,则肯定没有结果,直接剪枝。则 k-path.size()<n-i+1,所以i=n-(k-path.size())+1,也就是i的上界。

2. lc216 组合总和III

lc216 链接

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:只使用数字1到9,每个数字 最多使用一次 .返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次
输入: k = 3, n = 9 输出: [ [1,2,6], [1,3,5], [2,3,4] ]

Solution:
与上题相似,多了一个对sum的判断。可以选择的数字是1-9

 List<List<Integer>> res= new ArrayList<>();
 LinkedList<Integer> path = new LinkedList<>();
 public List<List<Integer>> combinationSum3(int k, int n) {
     backTrack(k,n,1,0);
     return res;
 }

 void backTrack(int k,int n,int startIndex,int sum)
 {
     // 剪枝操作,如果sum已经大于n,直接返回
     if(sum>n)
         return;
     
     // 终止条件
     if(path.size()==k)
     {
         if(sum==n)
             res.add(new ArrayList<>(path));

         return;
     }
     // 当然,这里也可以模仿上面再剪枝,写成i<=9-(k-path.size())+1
     for(int i=startIndex;i<=9;i++)
     {
         path.add(i);
         sum += i;
         backTrack(k,n,i+1,sum);
         path.removeLast();
         sum -= i;
     }
 }

3. lc39 组合总和

lc39 链接

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。candidates 中的 同一个 数字可以 无限制重复被选取 。
输入: candidates = [2,3,5], target = 8 输出: [ [2,2,2,2],[2,3,3],[3,5] ]

Solution:
与前两题组合不同(特别是组合总和III),这里选取的数字的可以重复的,想一想前两题是怎么控制不重复选的,startIndex!每次dfs时都加一,这样就确定了遍历起点。所以,当可以重复时,就不用加一了!
(如果要问为什么还需要startIndex,因为这还是组合问题啊,也就是不能走回头路,比如[1,2,3],目标和是4,你可以选[1,1,2],如果没有startIndex,当你到2的时候,又会有[2,1,1]的可能!)

 List<List<Integer>> res = new ArrayList<>();
 LinkedList<Integer> path  =new LinkedList<>();
 public List<List<Integer>> combinationSum(int[] candidates, int target) {
     backTrack(candidates,target,0,0);
     return res;
    
 }
 void backTrack(int[] candidates,int target,int sum,int startIndex)
 {     
     if(sum>=target)
     {
         if(sum==target)
            res.add(new ArrayList<>(path));
         return ;
     }
     for(int i=startIndex;i<candidates.length;i++)
     {
         path.add(candidates[i]);
         sum+=candidates[i];
         // 注意这里,因为可以重复,所以不需要i+1了
         backTrack(candidates,target,sum,i);
         sum-=candidates[i];
         path.removeLast();
     }
 }

4. lc40 组合总和II

lc40链接

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用 一次
输入: candidates = [2,5,2,1,2], target = 5,
输出: [ [1,2,2], [5] ]

Solution:
与上一题的区别在于如何去重,因为原始的候选集有重复元素,如果还是按照上面的思路的话,结果集肯定有重复的。解决方法是排序+相邻相等判断

  class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates); // 注意这里先排序
        dfs(candidates,target,0,0);
        return res;
    }
     public void dfs(int[] nums,int target,int sum,int startIndex)
    {
        if(sum>target) return;
        if(sum==target)
        {
            res.add(new LinkedList<>(path));
            return;
        }
        for(int i=startIndex;i<nums.length;i++)
        {
        // 注意这里的去重,当i不是startIndex时,要判断与前一个数字是否相同
            if(i>startIndex && nums[i]==nums[i-1])
               continue;
            path.add(nums[i]);
            sum+=nums[i];
            dfs(nums,target,sum,i+1);
            sum-=nums[i];
            path.removeLast();
        }
    }
}

可以用[1,2,2’]来区分,通过画回溯树理解

在这里插入图片描述

5. lc78 子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集
输入:nums = [1,2,3]
输出:[ [],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3] ]

Solution:
与组合题目不同的是,求子集实际上求的是树的所有节点(而非叶子节点)

 List<List<Integer>> res  =new ArrayList<>();
 LinkedList<Integer> path = new LinkedList<>();
  public List<List<Integer>> subsets(int[] nums) {
      backTrack(nums,0);
      return res;

  }
  void backTrack(int[] nums,int startIndex)
  {
      // 注意这里是直接添加,因为要添加的是所有节点(而非前面题目的叶子节点)
      res.add(new ArrayList<>(path));

      // 终止条件可加可不加(因为下面的for循环结束回溯就结束了)
     /* if (startIndex >= nums.length){
          return;
      }*/

      for(int i=startIndex;i<nums.length;i++)
      {
          path.add(nums[i]);
          backTrack(nums,i+1);
          path.removeLast();
      }
  }

6. lc90 子集II

力扣90链接

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集
输入:nums = [1,2,2] 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

Solution:
对比上题可以看出,这里需要考虑去重,所以与lc40 组合总和II 基本相同

    class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
        dfs(nums,n,0);
        return res;
    }
    public void dfs(int[] nums,int n,int startIndex)
    {
        res.add(new LinkedList<>(path));

        for(int i=startIndex;i<n;i++)
        {
            if(i>startIndex && nums[i]==nums[i-1])
              continue;

            path.add(nums[i]);
            dfs(nums,n,i+1);
            path.removeLast();
        }
    }
}

排列

1. 全排列I

力扣46链接

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

Solution:
终于来到排列了,排列和子集以及组合最大的不同就是排列可以位置不同,直接点,不需要startIndex!因为抽象成一个回溯树时,搜索起点只要没被选过就都可以,例如[1,2,3]选1,还剩[2,3],然后[1,2,3]选2,还剩[1,3],这时肯定就不用startIndex,而是直接for循环从0索引开始。
但这时又有个问题,你怎么知道选过的元素,如果知道的话,直接跳过就好了,所以used数组应运而生,标记一下哪些元素用过了。

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> permute(int[] nums) {
        int[] used = new int[nums.length]; // 也可以用bool类型
        Arrays.fill(used,0); // 0代表元素没有使用过
        dfs(nums,used);
        return res;
    }
    public void dfs(int[] nums,int[] used)
    {
        
        if(path.size()==nums.length)
        {
            res.add(new LinkedList<>(path));
            return;
        }
        for(int i=0;i<nums.length;i++)
        {
            // 注意这里的去重,佛如、循环只会傻傻的从头遍历,但是有些元素已经访问过了,直接跳过
            if(used[i]==1) continue;
            
            path.add(nums[i]);
            used[i]=1; // 用过了要记得标记一下哦!
            dfs(nums,used);
            used[i] = 0; // 回溯之后要还原
            path.removeLast();
        }
    }
}

2. 全排列II

力扣47链接

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列
输入:nums = [1,1,2]
输出:
[ [1,1,2],[1,2,1],[2,1,1] ]

Solution:
相比于上一题,又难了点。主要还是去重逻辑。联系上面的组合去重,肯定也可以排序+相邻判断,另外还需要used数组,判断前一个元素是否被选择。为什么会多这一步呢?
当出现重复元素时,比如输入 nums = [1,2,2’,2’‘],2’ 只有在 2 已经被使用的情况下才会被选择,同理,2’’ 只有在 2’ 已经被使用的情况下才会被选择,这就保证了相同元素在排列中的相对位置保证固定

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        int[] used = new int[nums.length];
        Arrays.fill(used,0);
        Arrays.sort(nums);
        dfs(nums,used);
        return res;

    }
     public void dfs(int[] nums,int[] used)
    {
        if(path.size()==nums.length)
        {
            res.add(new LinkedList<>(path));
            return;
        }
        for(int i=0;i<nums.length;i++)
        {
            if(used[i]==1) continue;

            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1]==0) {
                continue;
                }
            path.add(nums[i]);
            used[i]=1;
            dfs(nums,used);
            used[i] = 0;
            path.removeLast();
        }
    }
}

组合问题的应用

1.lc17 电话号码的字母组合

lc17 链接

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合
输入:digits = “23” 输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]

Solution:
与组合问题最大的区别在于结果集来自“不同的组合
首先需要建立一个映射,从字符2-9映射到字母,可以hash可以数组。注意本题的回溯树,第一层是第一个数字对应的字母。第二层是第一二数字对应的字母(有几个数字就有几层—深度),树的宽度却取决于数字对应的字母长度。

class Solution {
    List<String> res = new ArrayList<>();
    public List<String> letterCombinations(String digits) {
        if(digits.length()==0) return res;
        String[] map = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
        dfs(map,digits,0);
        return res;

    }
    StringBuilder sb = new StringBuilder();
    public void dfs(String[] map,String s,int index)
    {
        if(sb.length()==s.length())
        {
             res.add(sb.toString());
             return;
        }
        int digit = s.charAt(index)-'0'; // 对应的数字
        String str = map[digit];
        for(int i=0;i<str.length();i++)
        {
            sb.append(str.charAt(i));
            dfs(map,s,index+1);
            sb.deleteCharAt(sb.length()-1);
        }
        }   
}

2.lc131 分割回文串

描述:

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串

示例:

输入:s = “aab”
输出:[[“a”,“a”,“b”],[“aa”,“b”]]

Solution:

List<List<String>> res = new ArrayList<>();
LinkedList<String> path = new LinkedList<>();

public List<List<String>> partition(String s) {
        backTrack(s,0);
        return res;
}

 void backTrack(String s,int index)
    {
        // 终止条件
        if(index >= s.length())
        {
            res.add(new ArrayList<>(path));
            return;
        }

        for(int i=index;i<s.length();i++)
        {
            if(isPalindrome(s,index,i))
            {
                String str = s.substring(index,i+1);
                path.add(str);
            }
            else
            continue;

            backTrack(s,i+1);
            path.removeLast();
        }
 }
 
// 判断是否是回文,用双指针的方法
boolean isPalindrome(String s, int start, int end)
    {
        while(start <=end)
        {
            if(s.charAt(start)!=s.charAt(end))
            {
                return false;
            }
            start++;
            end--;
        }
        return true;
}

3. lc19 复原IP地址

描述:

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 ‘.’ 来形成

示例:

输入:s = “25525511135”
输出:[“255.255.11.135”,“255.255.111.35”]

Solution:

在这里插入代码片

岛屿问题&棋盘问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/19434.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《编程思维与实践》1070.复数幂

《编程思维与实践》1070.复数幂 题目 思路 思路比较简单,就是细节比较繁琐: ( a b i ) ( c d i ) ( a c − b d ) ( a d b c ) i (abi)(cdi)(ac-bd)(adbc)i (abi)(cdi)(ac−bd)(adbc)i , 利用该公式分实部和虚部进行计算结果即可. 由于涉及加减和正负号,所以在大整数结构…

致力于中小企业JavaEE企业级快速开发平台、后台框架平台

一、开源项目简介 J2eeFAST 是一个 Java EE 企业级快速开发平台&#xff0c; 致力于打造中小企业最好用的开源免费的后台框架平台 。系统基于&#xff08;Spring Boot、Spring MVC、Apache Shiro、MyBatis-Plus、Freemarker、Bootstrap、AdminLTE&#xff09;经典技术开发&…

亲测好用|甲方、专家和领导,用三维模型汇报方案如何投其所好?

身为设计方的你&#xff0c;有没有这样的经历&#xff1a; ➤ 一个非常优秀的方案未能被甲方采纳&#xff0c;反而甲方选择了一个不如自己的方案&#xff0c;造成了很大的遗憾&#xff1b; ➤ 在讲述自己的设计方案的时候&#xff0c;经常越说越散&#xff0c;甚至到了最后自…

应用在虚机和容器场景下如何优雅上下线

在生产场景中部署的服务提供者常因业务升级或其他场景需要下线和上线的部署操作&#xff0c;本文总结了应用在上下线过程中会遇到的典型问题&#xff0c;并思考在虚机和容器场景该如何处理这些问题&#xff0c;规避该过程中可能出现的服务消费者的请求失败&#xff0c;实现应用…

springboot文件上传

1.新建文件上传页面 在static目录中新建upload-test.html&#xff0c;上传页面代码如下所示&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>springboot文件上传测试</title> <…

mysql数据库的库操作 --2

目录 库操作 2.1&#xff1a;数据库的查看与创建与使用 2.2&#xff1a;字符集和效验规则 2.3&#xff1a;修改和删除数据库 2.4&#xff1a;数据库的备份和恢复 2.5&#xff1a;查看连接情况 库操作 2.1&#xff1a;数据库的查看与创建与使用 2.1.1&#xff1a;数据库…

Redis 持久化

文章目录 1. Redis 持久化2. RDB2.1 自动触发2.2 手动触发2.3 RDB 优点2.4 RDB 缺点2.5 RDB 文件修复2.6 总结 3. AOF3.1 AOF持久化工作流程3.2 AOF 缓冲区三种写回策略3.3 AOF 优点3.4 AOF 缺点3.5 AOF 重写机制3.6 AOF 重写原理3.7 总结 4. 混合持久化5. 纯缓存模式 1. Redis…

系统移植——linux内核移植——分析内核编译过程

uImage镜像文件 1.进入linux内核源码目录 ubuntuubuntu:~$ cd FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61/ 打开Makefile文件 vi Makefile 搜索include 因为 $(SRCARCH)->arm 所以上述指令为 arch/arm/Makefile 2.进入linux内核源码目录下,arch/arm目录下…

计网笔记 数据链路层 (1-2) 封装成帧、差错控制、流量控制与可靠传输、停止等待协议、后退N帧协议(GBN)、选择重传协议(SR)

文章目录 前言在这里插入图片描述 零、数据链路层基本概念一、功能0、数据链路层功能概述1、封装成帧和透明传输1.1封装成帧1.2 透明传输1.3组帧方法 2、数据链路层的差错控制2.0差错从何而来2.1位错&#xff08;比特错&#xff0c;1变成0&#xff0c;0变成1&#xff09;2.2帧错…

复习一周,面了京东和百度,不小心都拿了Offer...

我个人情况是5年软件测试经验&#xff0c;在家复习了一周&#xff0c;面了京东和百度&#xff0c;都顺利拿下offer&#xff0c;下面是我的面试经历分享&#xff0c;希望能带来一些不一样的启发和帮助。 两家公司最常问的就是下面这些问题&#xff1a; 请介绍一下你之前做过哪些…

String类

目录 一.认识 String 类 二.常用方法 1.字符串构造&#xff08;定义&#xff09; 2.字符串指为空和null 3.String对象的比较 &#xff08;1&#xff09;equals和的区别 &#xff08;2&#xff09;compareTo比较 4.字符串查找 5.字符串转化 &#xff08;1&#xff09;…

前几天面了个32岁的测试员,年薪50w问题基本都能回答上,应该刷了不少八股文···

互联网行业竞争是一年比一年严峻&#xff0c;作为测试工程师的我们唯有不停地学习&#xff0c;不断的提升自己才能保证自己的核心竞争力从而拿到更好的薪水&#xff0c;进入心仪的企业&#xff08;阿里、字节、美团、腾讯等大厂.....&#xff09; 所以&#xff0c;大家就迎来了…

centerpoint论文和代码解读

目录 一、序论 二、论文结构 三、代码 论文地址&#xff1a; https://arxiv.org/pdf/2006.11275.pdf 代码地址&#xff1a;tianweiy/CenterPoint (github.com) 一、序论 centorpoint是一种anchor-free的方法&#xff0c;直接预测物体的中心点&#xff0c;然后直接回归其wh…

【C++】unordered_map与unordered_set(系列关联式容器)

文章目录 1.unordered系列关联式容器2. unordered_map3.unordered_set 1.unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;如map和set&#xff0c;它们在查询时效率可达logN&#xff0c;即最差情况下需要比较红黑树的高度…

将 Segment Anything 扩展到医学图像领域

文章目录 前言技术交流SAM 拆解分析从医学角度理解 SAM 的效用MedSAM实验总结 前言 SAM 是一种在自然图像分割方面取得成功的模型&#xff0c;但在医学图像分割方面表现不佳。MedSAM 首次尝试将 SAM 的成功扩展到医学图像&#xff0c;并成为用于分割各种医学图像的通用工具。为…

一文读懂 DNS 解析

导读 文章为“一文读懂域名与网站系列”第二篇&#xff0c;上篇文章主要介绍了域名的注册、建站和管理&#xff0c;通过本文你可以了解以下几个问题&#xff1a; 域名的结构、常用解析记录的类型 DNS 解析的过程 DNS 解析拓展知识 众所周知&#xff0c;互联网中的地址其实是…

Invicti v23.5 for Windows 发布 - 企业应用安全测试

Invicti v23.5 for Windows - 企业应用安全测试 Invicti Standard 11 May 2023 v23.5.0.40516 请访问原文链接&#xff1a;https://sysin.org/blog/invicti/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Invicti 是一种自动…

ESP32在linux下烧录,提示权限有问题,解决方法

执行idf.py -p /dev/ttyACM0 flash下载时&#xff0c;提示这个错误 serial.serialutil.SerialException: [Errno 13] could not open port /dev/ttyACM0: [Errno 13] Permission denied: /dev/ttyACM0 解决方法&#xff1a; 1检查串行端口 /dev/ttyUSB0 是否已被其他程序占用…

系统分析师之项目管理(十七)

一、范围管理 范围管理&#xff1a;确定项目的边界&#xff0c;即哪些工作是项目应该做的&#xff0c;哪些工作不应该包括在项目中。 二、时间管理 时间管理&#xff1a;也叫进度管理&#xff0c;就是用科学的方法&#xff0c;确定目标进度&#xff0c;编制进度计划和资源供应计…

SpringBoot整合Swagger

Swagger的作用&#xff1a;生成前后的接口文档&#xff1a; 了解Swagger的概念及作用 掌握在项目中集成Swagger自动生成API文档 一、SpringBoot集成Swagger 1.依赖&#xff1a; <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --><depe…