算法套路十——回溯法之子集型回溯

news2024/9/22 23:37:05

算法套路十——回溯法之子集型回溯

算法实例一:LeetCode17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。在这里插入图片描述

首先介绍何为回溯法,如下图所示:
在这里插入图片描述
通俗的理解就是通过回溯来遍历所有情况,使用一个数组记录每种情况,且在递归完成后将该数组的内容回溯到,如图中如果目前记录了"ad"的情况,在这种情况枚举完成后,将数组中的“d“删除使数组中元素重新为“a”即是一种回溯,这样可以继续往数组中添加“e”;
当“a”的所有情况枚举完后,将数组中的“a”也删除回溯到数组为空,枚举第一个元素为“b”的情况。这样不断回溯,不断记录,就会枚举完所有的情况。

因此对与本题我们采用回溯法,用path记录当前枚举的情况,ans记录答案。

  • 当前问题:前i-1位固定,枚举大于等于 i 位的所有字母组合
  • 当前操作:i是否是n,若是则将path记录的情况加入ans中。若不是则枚举第i位所有可能字母,并将枚举的字母加入path,并递归子问题,且在子问题枚举完成后,需要进行回溯——将当前枚举的第i位字母从path删除,并判断第i位是否所有情况都枚举完,若不是则继续枚举当前情况,若是则结束当前问题,返回上层递归函数。
  • 子问题:枚举大于等于i+1的字母组合情况
MAPPING = "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"
class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        n=len(digits)
        if n == 0:
            return []
        ans=[]
        path=[]
        def dfs(i:int)->None:
            if i==n:
                ans.append("".join(path))
                return
            for c in MAPPING[int(digits[i])]:
                path.append(c)
                dfs(i + 1)
                path.pop()
        dfs(0)
        return ans    

算法实例二:LeetCode78. 子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
在这里插入图片描述

子集型问题分两种思路,一种是从输入的思路来考虑,如本题考虑当前元素是选还是不选,第二种是从答案的思路来考虑,如考虑选哪个元素

思路一:输入的思路(判断数组每个位置选或不选,直到数组最后一个元素)

在这里插入图片描述

采用回溯法,用path记录当前数字选择的情况,ans记录答案。

  • 当前问题:数组前i-1个元素是否选择固定,枚举数组从第i个元素开始的所有元素是否选择
  • 当前操作:i是否为n,若是则将当前path加入ans中。若不是则需要枚举子集选择第i位元素或不选第i位元素,若不选第i位元素,则直接递归子问题;若选择第i位元素,则需要先将当前元素加入path中,并递归子问题,在递归完成后,进行回溯,将第i位元素从path中删除
  • 子问题:数组前i-1个元素是否选择固定,枚举数组从第i+1个元素开始的所有元素是否选择
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        ans=[]
        path=[]
        n=len(nums)
        def dfs(i:int)->None:
            if i==n:
                ans.append(path.copy())# 固定答案
                return
            #不选 nums[i]
             dfs(i + 1)
            # 选 nums[i]
            path.append(nums[i])
            dfs(i + 1)
            path.pop() #恢复现场
        dfs(0)
        return ans    

思路二:答案的思路(枚举数组所有的选择情况,每次枚举都是答案)

采用回溯法,用path记录当前枚举的情况,ans记录答案。
在这里插入图片描述

  • 当前问题:枚举数组从第i位到最后的所有选择情况
  • 当前操作:每次枚举的path都是答案,故将当前枚举的path加入ans中,并判断是否枚举到最后一个元素,若是则返回;若不是则枚举j>=i,将数组第 j 位元素加入path中,并递归子问题,递归完成后,进行回溯,将数组第j位元素从path删除
  • 子问题:枚举数组从第 j+1 位到最后的所有选择情况
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        ans=[]
        path=[]
        n=len(nums)
        def dfs(i:int)->None:
            ans.append(path.copy())# 固定答案
            if i==n:
                return
            for j in range(i, n):  # 枚举选择的数字
                path.append(nums[j])
                dfs(j + 1)/#修改的值在当前dfs(j+1)内加入ans中,如本题即先选1
                path.pop() #恢复现场,恢复现场后的值将在下一次循环j的dfs(j+1)内加入ans中,即在下一次dfs时没有选择1,选择了2
        dfs(0)
        return ans   

总结:

虽然有两种思路,但可以看到仅仅在dfs递归函数中有代码修改,且一般退出递归的条件是一样的,只是在ans更新与何时递归有所不同

算法练习一:LeetCode784. 字母大小写全排列

给定一个字符串 s ,通过将字符串 s 中的每个字母转变大小写,我们可以获得一个新的字符串。返回 所有可能得到的字符串集合 。以 任意顺序 返回输出。在这里插入图片描述

思路一:输入的思路(判断字符串s每个字符是否转变大小写)

在这里插入图片描述

采用回溯法,用cur记录当前转变大小写的情况,ans记录答案。

  • 当前问题:判断字符串i之后的每个字符是否转变大小写
  • 当前操作:i是否小于n,若是则判断是否为数字,若是则i++,知道当前i不是数字或者直到 i=n,若i=n则将cur加入ans中,否则当前i位置为字符,则分为转变大小写与不转变大小写,并分别递归子问题
  • 子问题:判断字符串i+1之后的每个字符是否转变大小写
func letterCasePermutation(s string) []string {
    n:=len(s)
    ans:=[]string{}
    cur:=[]byte(s)
    var dfs func(i int)
    dfs=func(i int){
        for i<n&&cur[i]>='0'&&cur[i]<='9'{
            i++
        }
        if i==n{
            ans=append(ans,string(cur))
            return
        }
        //不转变
        dfs(i+1)
        //转变
        cur[i] ^= 32//异或 32 可进行字母大小写转换
        dfs(i+1)
        cur[i] ^= 32
       
    }
    dfs(0)
    return ans
}

思路二:答案的思路(枚举选择哪个字母进行转变,每次枚举都是答案)

在这里插入图片描述
采用回溯法,用cur记录当前枚举的情况,ans记录答案。

  • 当前问题:枚举字符串i位后的每个字符的转变情况
  • 当前操作:首先将记录的cur字符串计入ans中,之后枚举j从i到字符最后,判断第j位是否是字符,若不是则继续循环,若是则进行转变、递归、回溯
  • 子问题:枚举字符串第j+1位之后的分割情况
func letterCasePermutation(s string) []string {
    n:=len(s)
    ans:=[]string{}
    cur:=[]byte(s)
    var dfs func(i int)
    dfs=func(i int){
        ans=append(ans,string(cur))//每次枚举都是答案
        for j:=i;j<n;j++{
            if cur[j]>='0'&&cur[j]<='9'{
                continue    
            }
            cur[j] ^= 32
            dfs(j+1)
            cur[j] ^= 32
        }
    }
    dfs(0)
    return ans
}

算法练习二:LeetCode2397. 被列覆盖的最多行数

给你一个下标从 0 开始的 m x n 二进制矩阵 mat 和一个整数 cols ,表示你需要选出的列数。
如果一行中,所有的 1 都被你选中的列所覆盖,那么我们称这一行 被覆盖 了。
请你返回在选择 cols 列的情况下,被覆盖 的行数 最大 为多少。在这里插入图片描述

思路一:输入的思路(判断矩阵每列选或不选,直到矩阵最后一列或者剩余可选列数为0)

采用回溯法,用selectCols来记录当前选择的列数,用lines函数来计算当前列数选择情况下的覆盖行数,maxAns记录答案。

  • 当前问题:矩阵前i-1个列是否选择固定,枚举矩阵第i列之后的每个列是否选择
  • 当前操作:首先判断剩余可选列数是否为0,若是的话则判断maxAns是否需要更新,若不是则判断i==n,若等于则结束函数;之后分别谈论是否选择该列,若不选择则直接递归子函数,若选择则修改selectCols,并令numSelect–,之后递归子函数,递归完成后进行回溯
  • 子问题:矩阵前i个列是否选择固定,枚举矩阵第i+1列之后的每个列是否选择
func maximumRows(matrix [][]int, numSelect int) int {
    maxAns:=-1
    n:=len(matrix[0])
    selectCols:=[13]int{}
    var dfs func(i int)
    dfs=func(i int){
        if numSelect==0{
            maxAns=max(maxAns,lines(matrix,selectCols))
            return
        }else if i==n{
            return
        }
        //不选该列
        dfs(i+1)
        //选该列
        selectCols[i]=1
        numSelect--
        dfs(i+1)
        selectCols[i]=0
        numSelect++
    }
    dfs(0)
    return maxAns
}
func lines(matrix [][]int,selectCols [13]int) int{
    ans:=0
    m:=len(matrix)
    n:=len(matrix[0])
    for i:=0;i<m;i++{
        j:=0
        for ;j<n;j++{
            if matrix[i][j]==1{
                if selectCols[j]==1{continue}
                break
            }
        }
        if j==n{
            ans++
        }
    }
    return ans
}
func max(a,b int) int{if a>b{return a};return b}

思路二:答案的思路(枚举选择哪个列,需要满足矩阵最后一列或者剩余可选列数为0的要求)

采用回溯法,用selectCols来记录当前选择的列数,用lines函数来计算当前列数选择情况下的覆盖行数,maxAns记录答案。

  • 当前问题:枚举矩阵从第i位之后每列的选择情况
  • 当前操作:首先判断剩余可选列数是否为0,若是的话则判断maxAns是否需要更新,若不是则判断i==n,若等于则结束函数;之后枚举j从i到n,并对每个j列进行选择并更新selectCols,递归,回溯
  • 子问题:枚举字符串第j+1位之后每列的选择情况
func maximumRows(matrix [][]int, numSelect int) int {
    maxAns:=-1
    n:=len(matrix[0])
    selectCols:=[13]int{}
    var dfs func(i int)
    dfs=func(i int){
        if numSelect==0{
            maxAns=max(maxAns,lines(matrix,selectCols))
            return
        }else if i==n{
            return
        }
        for j:=i;j<n;j++{
            selectCols[j]=1
            numSelect--
            dfs(j+1)
            selectCols[j]=0
            numSelect++
        } 
    }
    dfs(0)
    return maxAns
}
func lines(matrix [][]int,selectCols [13]int) int{
    ans:=0
    m:=len(matrix)
    n:=len(matrix[0])
    for i:=0;i<m;i++{
        j:=0
        for ;j<n;j++{
            if matrix[i][j]==1{
                if selectCols[j]==1{continue}
                break
            }
        }
        if j==n{
            ans++
        }
    }
    return ans
}
func max(a,b int) int{if a>b{return a};return b}

算法练习三:LeetCode1601. 最多可达成的换楼请求数目

我们有 n 栋楼,编号从 0 到 n - 1 。每栋楼有若干员工。由于现在是换楼的季节,部分员工想要换一栋楼居住。
给你一个数组 requests ,其中 requests[i] = [fromi, toi] ,表示一个员工请求从编号为 fromi 的楼搬到编号为 toi 的楼。
一开始 所有楼都是满的,所以从请求列表中选出的若干个请求是可行的需要满足 每栋楼员工净变化为 0 。意思是每栋楼 离开 的员工数目 等于 该楼 搬入 的员工数数目。比方说 n = 3 且两个员工要离开楼 0 ,一个员工要离开楼 1 ,一个员工要离开楼 2 ,如果该请求列表可行,应该要有两个员工搬入楼 0 ,一个员工搬入楼 1 ,一个员工搬入楼 2 。
请你从原请求列表中选出若干个请求,使得它们是一个可行的请求列表,并返回所有可行列表中最大请求数目。1 <= n <= 20,,1 <= requests.length <= 16 ,requests[i].length == 2 ,0 <= fromi, toi < n
在这里插入图片描述

思路一:输入的思路(判断每个换房请求选或不选,直到请求最后一列)

采用回溯法,用m记录reques的长度,selects来记录当前选择的换楼请求,用isSatisfy函数来判断当前请求选择情况下是否符合要求,maxAns记录答案。

  • 当前问题:矩阵前i-1个请求是否选择固定,枚举矩阵第i列之后的每个请求是否选择
  • 当前操作:判断i是否等于m,若是则判断当前选择是否符合条件,若符合则更新maxAns,否则分情况选择当前请求i与不选择当前请求
  • 子问题:矩阵前i个请求是否选择固定,枚举矩阵第i+1列之后的每个请求是否选择
func maximumRequests(n int, requests [][]int) int {
    m:=len(requests)
    selects:=make([][]int,0)
    maxAns:=-1
    var dfs func(int) 
    dfs=func(i int) {
        if i==m{
            if isSatisfy(selects){
                maxAns=max(maxAns,len(selects))    
            }
            return
        }
        //不选
        dfs(i+1)
        //选
        selects=append(selects,append([]int{},requests[i]...))
        dfs(i+1)
        selects=selects[:len(selects)-1]
    }
    dfs(0)
    return maxAns
}
func max(a,b int)int{if(a>b){return a};return b}
func isSatisfy(selects [][]int) bool {
    cntFrom:=[21]int{}
    cntTo:=[21]int{}
    for _,request:=range selects{
        cntFrom[request[0]]++
        cntTo[request[1]]++
    }
    for i:=0;i<21;i++{
        if cntFrom[i]!=cntTo[i]{
            return false
        }
    }
    return true
}

思路二:答案的思路(枚举选换房请求的所有情况,每次枚举都判断是否更新maxAns)

采用回溯法,用m记录reques的长度,selects来记录当前选择的换楼请求,用isSatisfy函数来判断当前请求选择情况下是否符合要求,maxAns记录答案。

  • 当前问题:枚举从j到m的换房请求情况
  • 当前操作:判断是否符合要求,并判断是否需要更新maxAns;之后判断i==m,若等于则结束递归;否则枚举j从i到m,并记录,递归,回溯
  • 子问题:枚举从j+1到m的换房请求情况
func maximumRequests(n int, requests [][]int) int {
    m:=len(requests)
    selects:=make([][]int,0)
    maxAns:=-1
    var dfs func(int) 
    dfs=func(i int) {
        if isSatisfy(selects){
            maxAns=max(maxAns,len(selects))    
        }
        if i==m{
            return
        }
        for j:=i;j<m;j++{
            selects=append(selects,append([]int{},requests[j]...))
            dfs(j+1)
            selects=selects[:len(selects)-1]
        }
    }
    dfs(0)
    return maxAns
}
func max(a,b int)int{if(a>b){return a};return b}
func isSatisfy(selects [][]int) bool {
    cntFrom:=[21]int{}
    cntTo:=[21]int{}
    for _,request:=range selects{
        cntFrom[request[0]]++
        cntTo[request[1]]++
    }
    for i:=0;i<21;i++{
        if cntFrom[i]!=cntTo[i]{
            return false
        }
    }
    return true
}

算法进阶一:LeetCode131. 分割回文串

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

思路一:输入的思路(判断字符串每个位置是否分割,直到字符串最后一个元素)

在这里插入图片描述

采用回溯法,用path记录当前分割情况,ans记录答案。

  • 当前问题:判断字符串i之后的每个位置是否进行分割,且使用start记录上一次分割后的开始字符,方便判断是否回文
  • 当前操作:i是否为n,若是则将当前path加入ans中。首先判断i是否是最后一位字符,若是则必须进行分割。
    若不是,则分别考虑是否分割,若不分割,则直接调用下一个子问题;若分割,则利用start记录的上一个分割后的开始字符判断当目前字符是否为回文数,若不是则直接跳过,若是则将分割字符加入path中,并调用子问题,且令start为下一位字符i+1,递归完成后恢复现场
  • 子问题:判断字符串i+1之后的位置否进行分割,且使用start记录上一个分割的位置,方便判断是否回文
func partition(s string) (ans [][]string) {
    path:=[]string{}
    n:=len(s)
    var  dfs func( int,int )
    dfs=func(i ,start int ){    
        if i==n{
            ans=append(ans,append([]string{},path...))
            return
        }
        // 不选 i 和 i+1 之间的逗号(i=n-1 时已到字符串末尾,必须进行分割)
        if i < n-1 {
            dfs(i+1,start)
        }
        // 选 i 和 i+1 之间的逗号
        if isPalindrome(s,start,i){
            path=append(path,s[start:i+1])
            dfs(i+1,i+1)
            path = path[:len(path)-1] // 恢复现场
        }
    }
    dfs(0,0)
    return 
}
func isPalindrome(s string, left, right int) bool {
    for left < right {
        if s[left] != s[right] {
            return false
        }
        left++
        right--
    }
    return true
}

思路二:答案的思路(枚举字符串下一个位置在哪分割,枚举到字符串最后一个元素)

采用回溯法,用path记录当前枚举的情况,ans记录答案。

  • 当前问题:枚举字符串第i位之后的分割情况
  • 当前操作:注意此题需分割到最后一个位置这样才能确实是否是分割串都是回文串,而不是每个节点都是答案,即i是否为n,若是则将当前path加入ans中。之后循环枚举j从i到n-1为分割结束位置,并判断s[i:j+1]是否为回文串,若是则path记录,递归j+1,回溯
  • 子问题:枚举字符串第j+1位之后的分割情况
func partition(s string) (ans [][]string) {
    path:=[]string{}
    n:=len(s)
    var  dfs func( int)
    dfs=func(i int){    
        if i==n{
            ans=append(ans,append([]string{},path...))
            return
        }
        for j:=i;j<n;j++{// 枚举子串的结束位置
            if isPalindrome(s,i,j){
                path=append(path,s[i:j+1])
                dfs(j+1)
                path=path[:len(path)-1]
            }
        }
    }
    dfs(0)
    return 
}
func isPalindrome(s string, left, right int) bool {
    for left < right {
        if s[left] != s[right] {
            return false
        }
        left++
        right--
    }
    return true
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Spring Boot】spring boot 项目的创建

目录 一.本地创建 二.官网创建 一&#xff1a;本地创建 1. 2. 3. 4. 5. 6. 选择相应的版本&#xff0c;并点击next 7. 8. 9. 二.官网创建 1. 点击链接进入官网 2. 3. 5. 6.

【进阶C语言】动态内存管理

前言 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐的一位博主。 &#x1f4d7;本文收录于C语言进阶系列&#xff0c;本专栏主要内容为数据的存储、指针的进阶、字符串和内存函数…

win10 专业版登录Microsoft账户提示:0x800704cf 错误代码——问题解决记录

win10 专业版登录Microsoft账户提示&#xff1a;0x800704cf 错误代码——问题解决记录 系统版本 版本 Windows 10 专业版 版本号 21H2 安装日期 ‎2021/‎5/‎7 操作系统内部版本 19044.2846 体验 Windows Feature Experience Pack 120.2212.4190.0 问题描述 曾经手动修改过…

《程序员面试金典(第6版)》面试题 10.11. 峰与谷(双指针,贪心思想)

题目描述 在一个整数数组中&#xff0c;“峰”是大于或等于相邻整数的元素&#xff0c;相应地&#xff0c;“谷”是小于或等于相邻整数的元素。例如&#xff0c;在数组{5, 8, 4, 2, 3, 4, 6}中&#xff0c;{8, 6}是峰&#xff0c; {5, 2}是谷。现在给定一个整数数组&#xff0c…

网络原理IP协议

hi,大家好,小魏又来了,我们已经认识了UDP,TCP,现在来认识一下位于网络层的协议,IP 认识IP地址 1.地址管理 2.路由选择 在之前的讲解中我们已经认识到了网络层的IP协议,负责寻路操作 IP地址&#xff08;Internet Protocol Address&#xff09;是指互联网协议地址&#xff0…

【Java版oj】day35年会抽奖、抄送列表

目录 一、年会抽奖 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 二、抄送列表 &#xff08;1&#xff09;原题再现 &#xff08;2&#xff09;问题分析 &#xff08;3&#xff09;完整代码 一、年会抽奖 …

C++ 命名空间 输入输出 缺省参数 引用 函数重载

在学习C之前&#xff0c;我们要先知道C和C是向上兼容的&#xff0c;也就是说&#xff0c;在cpp文件中既可以写入C的代码&#xff0c;也可以写C的代码&#xff0c;在日常编写代码中&#xff0c;经常会出现C和C混编的情况。 此博客都是在 C 的缺陷的基础之上 整理 C 中对其的优化…

PyTorch 之 强大的 hub 模块和搭建神经网络进行气温预测

文章目录一、强大的 hub 模块1. hub 模块的使用2. hub 模块的代码演示二、搭建神经网络进行气温预测1. 数据信息处理2. 数据图画绘制3. 构建网络模型4. 更简单的构建网络模型本文参加新星计划人工智能(Pytorch)赛道&#xff1a;https://bbs.csdn.net/topics/613989052 一、强…

机器学习——回归与聚类算法

线性回归 广义的线性模型 不仅是自变量是一次方的是线性模型&#xff0c;参数是一次方的也是线性模型&#xff0c;比如&#xff1a; 总结&#xff1a;线性关系的一定是线性模型&#xff0c;线性模型的不一定是线性关系。 损失函数 优化损失 求解模型中的w&#xff0c;使得…

SeNet论文解读/总结

此文章为深度学习在计算机视觉领域的图片分类经典论文SeNet&#xff08;Squeeze-and-Excitation Networks&#xff09;论文总结。 此系列文章是非常适合深度学习领域的小白观看的图像分类经典论文。系列文章如下&#xff1a; AlexNet&#xff1a;AlexNet论文解读/总结_alexnet…

uniapp-搜索配置

自定义搜索组件 1.定义组件的 UI 结构: <template><!-- 通过属性绑定的形式&#xff0c;为 .my-search-container 盒子和 .my-search-box 盒子动态绑定 style 属性 --><view class"my-search-container" :style"{background-color: bgcolor}&q…

《花雕学AI》23:中文调教ChatGPT的秘诀:体验测试与通用案例,解锁无限有趣玩法!

引言&#xff1a; 你有没有想过和一台智能机器人聊天&#xff1f;你有没有想过让一台智能机器人为你创作诗歌、故事或歌曲&#xff1f;你有没有想过让一台智能机器人陪你玩游戏、学习或社交&#xff1f;如果你的答案是肯定的&#xff0c;那么你一定会对ChatGPT感兴趣。 ChatG…

Hystrix详解

前言 Hystrix基于Feign&#xff0c;想熟悉Hystrix&#xff0c;必须先熟悉Feign。 Feign&#xff08;简介和使用&#xff09;&#xff1a; Feign&#xff08;简介和使用&#xff09;_长头发的程序猿的博客-CSDN博客 Hystrix简介 hystrix对应的中文名字是“豪猪”&#xff0c…

Android开发 Camera2获取输出SurfaceTexture

目录 一、Camera2概述 1 Pipeline 2 CameraManager 3 CameraDevice 4 CameraCharacteristics 5 CameraCaptureSession 6 CaptureRequest 7 Surface 8 CaptureResult 三、Camera2的特性 1 Camera2 才支持的高级特性 2 Camera1 迁移到 Camera2 二、示例源码 一、Came…

Honggfuzz Linux arch_clone 源码阅读 (setjmp, clone)

Honggfuzz Linux arch_clone 源码阅读 &#xff08;setjmp, clone&#xff09; 阅读 Honggfuzz 系统架构相关源码&#xff0c;在创建子进程部分遇到了几个问题&#xff0c;经过研究得以解决&#xff0c;在此记录。 Source Code 代码节选自linux/arch.c&#xff0c;已添加注释&…

RabbitMq 消息可靠性问题(一) --- publisher发送时丢失

前言 消息从生产者发送到exchange, 再到 queue, 再到消费者。这个过程中有哪些有消息丢失的可能性呢&#xff1f; 发送时丢失&#xff1a; 生产者发送的消息未送达 exchange消息到达 exchange 后未到达 queue MQ 宕机&#xff0c;queue将消息丢失consumer 接收到消息后未消费…

聊聊如何运用JAVA注解处理器(APT)

什么是APT APT&#xff08;Annotation Processing Tool&#xff09;它是Java编译期注解处理器&#xff0c;它可以让开发人员在编译期对注解进行处理&#xff0c;通过APT可以获取到注解和被注解对象的相关信息&#xff0c;并根据这些信息在编译期按我们的需求生成java代码模板或…

基于DistFlow的含分布式电源配电网优化模型【IEEE39节点】(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

SpringBoot【基础篇】---- SSMP整合综合案例

SpringBoot【基础篇】---- SSMP整合综合案例1. 模块创建2. 实体类开发3. 数据层开发----基于CRUD查看MP运行日志查看 MP 的运行日志4. 数据层开发----分页功能制作5. 数据层开发----条件查询功能制作6. 业务层开发业务层快速开发7. 表现层开发8. 表现层消息一致性处理9. 前后端…

STC32G单片机内置ADC及应用编程

一 STC32G单片机内置ADC模块简介 STC32G单片机内部集成了一个12位高速ADC转换器&#xff0c;ADC的最高时钟频率为系统频率的1/2。其输入通道多达15个&#xff08;第15通道为专门测量内部1.19V参考信号源的通道&#xff09;&#xff0c;可分时切换使用。 STC15系列单片机内置AD…