LeetCode刷题小记 八、【回溯算法】

1.回溯算法

文章目录

    • 1.回溯算法
    • 写在前面
      • 1.1回溯算法基本知识
      • 1.2组合问题
      • 1.3组合问题的剪枝操作
      • 1.4组合总和III
      • 1.5电话号码的字母组合
      • 1.6组合总和
      • 1.7组合总和II
      • 1.8分割回文串
      • 1.9复原IP地址
      • 1.10子集问题
      • 1.11子集II
      • 1.12非递减子序列
      • 1.13全排列
      • 1.14全排列II
      • 1.15N皇后
      • 1.16解数独

写在前面

本系列笔记主要作为笔者刷题的题解,所用的语言为Python3,若于您有助,不胜荣幸。

1.1回溯算法基本知识

回溯算法也叫回溯搜索法,是一种搜索方法,回溯算法虽然难以理解,但是其并不高效,因为回溯的本质是穷举,穷举所有的可能,然后限制条件获得我们的想要的结果。想要回溯算法高效一点可以添加一些剪枝的操作,但是这并不能改变回溯算法的本质。

回溯算法一般用于解决以下的问题:

  • 组合问题:N个数里面按照一定规则找出k个数的集合
  • 切割问题:一个字符串按照一定规则有几种切割方式
  • 子集问题:一个N个数的集合里有多少种符合条件的子集
  • 排列问题:N个数按照一定规则全排列,有多少种排列方式
  • 棋盘问题:N皇后,解数独等。

回溯算法一般具有以下的模板:

  • 回溯函数模板返回值及参数

回溯算法中函数的返回值一般为空None,回溯算法的参数不会像二叉树递归那样容易确定,一般是先写逻辑,然后需要什么参数的时候再进行修改。

回溯函数的函数定义一般如下:

def backtracking(参数) -> None:
  • 回溯函数的终止条件

回溯函数一定是树形结构的,所有一定有终止条件,满足一定的终止条件的时候,我们就应该进行返回了,一般是我们遇到叶子节点的时候,这时候就要收集结果了,所以回溯函数终止条件的伪代码如下:

if 终止条件:存放结果return
  • 回溯搜索的遍历过程

回溯法一般是再集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成了树的深度。

回溯函数遍历过程伪代码如下:

for 选择:本层集合中元素:处理节点backtracking(路径, 选择列表)回溯,撤销处理结果

所以回溯法的整体结构如下:

def backtracking(参数) -> None:if 终止条件:存放结果returnfor 选择:本层集合中元素(树中节点孩子的数量就是集合的大小):处理节点backtracking(路径, 选择列表) # 递归回溯,撤销处理结果

回溯算法相当于是递归算法里面还嵌套了for循环。

1.2组合问题

77. 组合

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

思路:中说到回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了,我们可以将回溯算法抽象成下列的一个二叉树,当我们在叶子节点的时候,我们就可以收获结果了,就得到了所有的组合。

Image

如何确定终止条件呢?遇到叶子节点的时候就终止了,其实这个时候我们用于保存中间结果的path的长度为k,所以我们可以进行判断if len(path) == k:,如果满足条件则遇到叶子节点可以保存结果。

class Solution:def __init__(self):self.res: List[List[int]] = []self.path: List[int] = []def backtracking(self, n: int, k: int, startIndex: int) -> None:if len(self.path) == k:                 # 终止条件,收获结果self.res.append(self.path[:])       # 这里需要进行copyreturnfor i in range(startIndex, n):          # 循环遍历self.path.append(i+1)self.backtracking(n, k, i+1)self.path.pop()def combine(self, n: int, k: int) -> List[List[int]]:self.backtracking(n, k, 0)return self.res

1.3组合问题的剪枝操作

77. 组合

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

思路:回溯算法的剪枝一般是在回溯搜索的过程中进行的,来举一个例子,n = 4,k = 4的话,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。 在第二层for循环,从元素3开始的遍历都没有意义了。

Image

所以,可以剪枝的地方就在递归中每一层的for循环所选择的起始位置

这个剪枝的条件可以则么看:

当前已经选择的元素个数为len(self.path),还需要选择的元素个数为k-len(self.path),列表中剩余元素的个数为(n-i),剩余元素的个数一定要大于等于所需要的元素的个数即(n-i) >= k - len(self.path),则有i <= n-(k-len(self.size)),这里由于range()函数是一个左闭右开的函数,所以我们这里的值应该设为range(startIndex, n-(k-len(self.path))+1)

class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, n: int, k: int, startIndex: int) -> None:if len(self.path) == k:self.res.append(self.path[:])return for i in range(startIndex, n-(k-len(self.path))+1):     # 剪枝操作self.path.append(i+1)self.backtracking(n, k, i+1)self.path.pop()def combine(self, n: int, k: int) -> List[List[int]]:self.backtracking(n, k, 0)return self.res

1.4组合总和III

216. 组合总和 III

找出所有相加之和为 nk 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

思路k控制树的深度,而n控制树的宽度

Image
class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, targetSum: int, Sum: int, k: int, startIndex: int) -> None:if len(self.path) == k:                 # 终止条件if Sum == targetSum:                # 收获结果self.res.append(self.path[:])returnfor i in range(startIndex, 9-(k-len(self.path))+1):                      # 循环遍历,进行剪枝限制至少有k个元素self.path.append(i+1)self.backtracking(targetSum, Sum+i+1, k, i+1)   # 显式回溯self.path.pop()def combinationSum3(self, k: int, n: int) -> List[List[int]]:self.backtracking(n, 0, k, 0)return self.res

1.5电话号码的字母组合

17. 电话号码的字母组合

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

1 1 1 2 a b c 2_{abc} 2abc 3 d e f 3_{def} 3def
4 g h i 4_{ghi} 4ghi 5 j k l 5_{jkl} 5jkl 6 m n o 6_{mno} 6mno
7 p q r s 7_{pqrs} 7pqrs 8 t u v 8_{tuv} 8tuv 9 w x y z 9_{wxyz} 9wxyz
∗ * 0 0 0#

思路:我们这里遍历的是两个集合,所以不需要startIndex来去重,但是需要一个index来指向当前遍历的数字

解法一:使用list来保存结果

class Solution:def __init__(self):self.str_map: List[str] = ["",         # 0"",         # 1"abc",      # 2"def",      # 3"ghi",      # 4"jkl",      # 5"mno",      # 6"pqrs",     # 7"tuv",      # 8"wxyz"      # 9]self.res: List[str] = []self.path: List[str] = []def backtracking(self, digits: str, index: int) -> None:if index == len(digits):self.res.append(''.join(self.path))returnletters: str = self.str_map[int(digits[index])]for char in letters:self.path.append(char)self.backtracking(digits, index+1)self.path.pop()def letterCombinations(self, digits: str) -> List[str]:if not digits:return []self.backtracking(digits, 0)return self.res

解法二:精简回溯,将s作为参数

class Solution:def __init__(self):self.str_map: List[str] = ["",         # 0"",         # 1"abc",      # 2"def",      # 3"ghi",      # 4"jkl",      # 5"mno",      # 6"pqrs",     # 7"tuv",      # 8"wxyz"      # 9]self.res: List[str] = []def backtracking(self, digits: str, index: int, s: str) -> None:if index == len(digits):self.res.append(s)returnletters: str = self.str_map[int(digits[index])]for char in letters:self.backtracking(digits, index+1, s+char)def letterCombinations(self, digits: str) -> List[str]:if not digits:return []self.backtracking(digits, 0, "")return self.res

1.6组合总和

39. 组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

思路:对于前面进行选择的元素,我们可以重复地选取,对于后面选取的元素,我们不能进行重复选取,我们需要用一个index参数来控制每次选取的位置,这个参数和startIndex还不太一样,每次更新的时候,我们需要设置index=i

对于组合问题,什么时候需要starIndex来控制for循环的起始位置,什么时候不需要呢?举个例子,如果是一个集合来求组合的话,就需要startIndex,如果是多个集合来求组合的话,各个集合之间互不影响,这时就不需要用startIndex了。

class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, candidates: List[int], targetSum: int, Sum: int, index: int) -> None:if Sum > targetSum:         # 剪枝return elif Sum == targetSum:      # 叶子节点并收获结果self.res.append(self.path[:])return for i in range(index, len(candidates)):self.path.append(candidates[i])self.backtracking(candidates, targetSum, Sum+candidates[i], i)          # 注意这里index的修改为iself.path.pop()def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:if not candidates:return []self.backtracking(candidates, target, 0, 0)return self.res

1.7组合总和II

40. 组合总和 II

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次

思路:这道题已经明确表示了会出现重复的元素,所以我们需要进行去重操作,如何进行去重呢?我们先对整个candidates进行排序,如果后一个遍历的元素,等于前一个遍历的元素,那么则跳过当前遍历的过程,因为对前一个元素的处理过程相当于已经处理过当前的元素了。

class Solution:def __init__(self):self.res: List[List[int]] = []self.path: List[int] = []def backtracking(self, candidates: List[int], targetSum: int, Sum: int, startIndex: int) -> None:if Sum > targetSum:                                                 # 剪枝return elif Sum == targetSum:self.res.append(self.path[:])return for i in range(startIndex, len(candidates)):if i > startIndex and candidates[i] == candidates[i-1]:          # 要对同一树层使用过的元素进行跳过,进行树层去重,跳过当前处理的元素continueself.path.append(candidates[i])self.backtracking(candidates, targetSum, Sum+candidates[i], i+1)        self.path.pop()def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:if not candidates:return []candidates.sort()                                           # 首先让当前元素有序self.backtracking(candidates, target, 0, 0)return self.res

1.8分割回文串

131. 分割回文串

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串(回文串是向前和向后读都相同的字符串) 。返回 s 所有可能的分割方案。

class Solution:def __init__(self):self.path: List[str] = []self.res: List[List[str]] = []def isPalidrome(self, s: str, start: int, end: int) -> bool:"""判断是否是回文数"""if start > end:return Falsewhile start < end:if s[start] == s[end]:start += 1end -= 1else:return Falsereturn Truedef backtracking(self, s: str, startIndex: int) -> None:if startIndex == len(s):self.res.append(self.path[:])for i in range(startIndex, len(s)):if self.isPalidrome(s, startIndex, i):      # 如果是回文串则加入到中间结果中self.path.append(s[startIndex:i+1])     # 注意这里的区间是左闭右开self.backtracking(s, i+1)self.path.pop()else:continuedef partition(self, s: str) -> List[List[str]]:if not s:return []self.backtracking(s, 0)return self.res

1.9复原IP地址

93. 复原 IP 地址

有效 IP 地址 正好由四个整数(每个整数位于 0255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

  • 例如:"0.1.2.201" "192.168.1.1"有效 IP 地址,但是 "0.011.255.245""192.168.1.312""192.168@1.1"无效 IP 地址。

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

class Solution:def __init__(self):self.path: List[str] = []self.res: List[str] = []def isVaild(self, s: str, start: int, end: int) -> bool:"""判断切割是否合法"""if end - start >= 1 and s[start] == '0':return Falsereturn True if int(s[start:end+1]) <= 255 else Falsedef backtracking(self, s: str, startIndex: int) -> None:if len(self.path) == 4 and startIndex == len(s):        # 终止条件self.res.append('.'.join(self.path))returnfor i in range(startIndex, len(s)):if self.isVaild(s, startIndex, i):self.path.append(s[startIndex:i+1])self.backtracking(s, i+1)self.path.pop()else:continuedef restoreIpAddresses(self, s: str) -> List[str]:if not s:return []self.backtracking(s, 0)return self.res

1.10子集问题

78. 子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的

子集(幂集)。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

思路:在解决子集问题的时候,我们需要时刻进行结果的收获,一个问题的就是,我们需要收获的结果不全是叶子节点,我们只要遇到结果就进行收获,所以收获节点会放在终止条件之前。

class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, nums: List[int], startIndex: int) -> None:self.res.append(self.path[:])           # 只要是节点就满足条件,收获结果在终止条件之前if startIndex == len(nums):return for i in range(startIndex, len(nums)):self.path.append(nums[i])self.backtracking(nums, i+1)self.path.pop()def subsets(self, nums: List[int]) -> List[List[int]]:self.backtracking(nums, 0)return self.res

1.11子集II

90. 子集 II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的

子集(幂集)。解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

思路:这道题涉及到去重,我们一般有两种去重的思路,第一种思路是直接对子集进行排序,判断后一个元素是否等于前一个元素,如果是则表明已经处理过相同的元素,则可以直接跳过;第二种思路是用一个set来完成去重,set可以用于树层的去重,在每一层我都建立一个set,如果在当前层中遍历的元素在这个set中,则表明已经使用过该元素,则跳过,反之则继续使用。

解法一:回溯+排序去重

class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, nums: List[int], startIndex: int) -> None:self.res.append(self.path[:])if startIndex == len(nums):returnfor i in range(startIndex, len(nums)):if i > startIndex and nums[i] == nums[i-1]:             # 进行排序去重continueelse:self.path.append(nums[i])self.backtracking(nums, i+1)self.path.pop()def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:nums.sort()self.backtracking(nums, 0)return self.res

解法二:回溯+set去重

class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, nums: List[int], startIndex: int) -> None:self.res.append(self.path[:])if startIndex == len(nums):returnuset: set = set()for i in range(startIndex, len(nums)):if nums[i] in uset:             # 用set进行去重continueelse:uset.add(nums[i])self.path.append(nums[i])self.backtracking(nums, i+1)self.path.pop()def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:nums.sort()							# 用set去重也要排序self.backtracking(nums, 0)return self.res

1.12非递减子序列

491. 非递减子序列

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

思路:我们收集结果的时候,也是在终止条件之前,唯一的要求就是当前的至少有两个元素,并且我们还要对同一树层进行去重,这里不能使用排序比较大小去重,因为我们不能对这个序列进行排序,如果进行排序了那么整个结果的顺序就改变了,所以我们只能用set进行去重。

class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, nums: List[int], startIndex: int) -> None:if len(self.path) >= 2:self.res.append(self.path[:])if startIndex == len(nums):return uset: set = set()for i in range(startIndex, len(nums)):if (self.path and nums[i] < self.path[-1]) or nums[i] in uset:      # 判断是否是非递减序列,或者在当前层中当前元素没有被使用continueelse:uset.add(nums[i])self.path.append(nums[i])self.backtracking(nums, i+1)self.path.pop()def findSubsequences(self, nums: List[int]) -> List[List[int]]:self.backtracking(nums, 0)return self.res

1.13全排列

46. 全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

思路:通常的思路是,对于每个树的分支,我们都维护一个used数组,如果其中的对应下表的元素被使用过,那么在当前树枝接下来的选取中,我们就跳过这个元素,并且我们将这个used数组沿着树的深度进行传播,同样需要进行回溯,为什么在排列问题中不使用startIndex呢?因为在组合问题中我们使用startIndex是为了避免后面的元素在同一树层中取之前取过的元素,用startIndex来进行限制,全排列问题,我们不需要进行这一限制,所以不需要startIndex总结一句话组合问题需要用startIndex,排列问题不需要startIndex

class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, nums: List[int], used: List[bool]) -> None:if len(self.path) == len(nums):self.res.append(self.path[:])returnfor i in range(len(nums)):                  # 排列问题,不需要使用startIndex来限制树层中取重复元素if used[i] == True:continueelse:used[i] = Trueself.path.append(nums[i])self.backtracking(nums, used)self.path.pop()                     # 回溯used[i] = False                     # 回溯def permute(self, nums: List[int]) -> List[List[int]]:used: List[bool] = [False] * len(nums)self.backtracking(nums, used)return self.res

1.14全排列II

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

思路:利用set进行树层去重,利用used进行树枝去重

解法一:利用set进行树层去重,利用used进行树枝去重

class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, nums: List[int], used: List[bool]):if len(self.path) == len(nums):self.res.append(self.path[:])return uset: set = set()                           # 利用set进行树层去重,利用used进行树枝去重for i in range(len(nums)):if nums[i] in uset or used[i] == True:continueelse:uset.add(nums[i])                   used[i] = Trueself.path.append(nums[i])self.backtracking(nums, used)self.path.pop()                     # 回溯used[i] = False                     # 回溯def permuteUnique(self, nums: List[int]) -> List[List[int]]:used: List[bool] = [False] * len(nums)self.backtracking(nums, used)return self.res

解法二:利用排列进行树层去重,利用used进行树枝去重

class Solution:def __init__(self):self.path: List[int] = []self.res: List[List[int]] = []def backtracking(self, nums: List[int], used: List[bool]):if len(self.path) == len(nums):self.res.append(self.path[:])return                          for i in range(len(nums)):                  if (i > 0 and nums[i] == nums[i-1] and used[i-1] == False ) or used[i] == True:  # 利用排列进行树层去重,利用used进行树枝去重,这里一定要used[i-1]==False才能保证是在树层上进行去重,这种解法比较复杂,不如解法一continueelse:                used[i] = Trueself.path.append(nums[i])self.backtracking(nums, used)self.path.pop()                     # 回溯used[i] = False                     # 回溯def permuteUnique(self, nums: List[int]) -> List[List[int]]:used: List[bool] = [False] * len(nums)nums.sort()self.backtracking(nums, used)return self.res

1.15N皇后

51. N 皇后

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

思路:我们需要对棋盘进行二维的一个遍历,在回溯算法模板的for循环中,即回溯算法的树层中,我们来遍历这个棋盘的col,在回溯算法的深度中,即回溯算法的树深中,我们来遍历这个棋盘的row,然后通过一个isValid()函数来判断当前的位置是否合法,如果合法我们就放置皇后Q,如果非法我们就继续搜索,最后当我们遍历完所有的row之后,我们即可以保存搜索的结果了,然后再进行回溯,这样我们就能够搜索所有想要的结果。

class Solution:def __init__(self):self.res: List[List[str]] = []def isValid(self, chessboard: List[List[str]], row: int, col: int) -> bool:# 检查相同列for i in range(row):                # 相同col的前n row已经有Q,则非法if chessboard[i][col] == 'Q':return False# 检查相同行for j in range(col):if chessboard[row][j] == 'Q':return False# 检查45°方向i = row - 1j = col - 1while i >=0 and j >=0:if chessboard[i][j] == 'Q':return Falsei -= 1j -= 1# 检查135°方向i = row - 1j = col + 1while i >= 0 and j < len(chessboard):if chessboard[i][j] == 'Q':return Falsei -= 1j += 1return Truedef backtracking(self, chessboard: List[List[str]], n: int, row: int) -> None:if row == n:                # 遍历完所有行则收集结果self.res.append(chessboard[:])return # 通过树层来遍历colfor col in range(n):if self.isValid(chessboard, row, col):# print(chessboard)chessboard[row] = chessboard[row][:col] + 'Q' +chessboard[row][col+1:]self.backtracking(chessboard, n, row+1)                                     # 通过树深来遍历rowchessboard[row] = chessboard[row][:col] + '.' +chessboard[row][col+1:]      # 回溯def solveNQueens(self, n: int) -> List[List[str]]:chessboard: List[List[str]] = ['.'*n]*nself.backtracking(chessboard, n, 0)return self.res

1.16解数独

37. 解数独

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

数独部分空格内已填入了数字,空白格用 '.' 表示。

解法一:双重for循环

class Solution:def isValid(self, board: List[List[str]], num: int, row: int, col: int) -> bool:# 当前列是否有效for i in range(len(board)):if board[i][col] == str(num):return False# 当前行是否有效for j in range(len(board)):if board[row][j] == str(num):return False# 当前方格是否有效start_row = (row // 3) * 3start_col = (col // 3) * 3for i in range(start_row, start_row+3):for j in range(start_col, start_col+3):if board[i][j] == str(num):return Falsereturn Truedef backtracking(self, board: List[List[str]]) -> bool:for i in range(len(board)):for j in range(len(board[0])):if board[i][j] != '.':continueelse:for num in range(1,10):if self.isValid(board, num, i, j):board[i][j] = str(num)if self.backtracking(board): return Trueboard[i][j] = '.'               # 回溯return False # 若数字1-9都不能成功填入空格,返回False无解return True # 有解def solveSudoku(self, board: List[List[str]]) -> None:"""Do not return anything, modify board in-place instead."""self.backtracking(board)

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

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

相关文章

react中hooks使用限制

只能在最顶层使用Hook 不要在循环、条件中调用hook&#xff0c;确保总是在React函数最顶层使用它们 只能React函数中调用Hook 不要在普通的js函数中调用 在React的函数组件中调用Hook 在自定义hook中调用其他hook 原因&#xff1a; 我们每次的状态值或者依赖项存在哪里&…

springCloudeAlibaba的使用

父pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…

数据库中逻辑运算符的介绍以及优先级表

简介&#xff1a;逻辑运算符主要判断表达式的真假&#xff0c;返回值为1&#xff0c;0&#xff0c;null 其中包含&#xff1a; 逻辑非&#xff1a;not或&#xff01; 逻辑与&#xff1a;and或&& 逻辑或&#xff1a;or或|| 逻辑异或&#xff1a;XOR 1.逻辑非运算 规则…

mac打开exe文件的三大方法 mac怎么运行exe文件 mac打开exe游戏 macbookpro打开exe

exe文件是Windows系统的可执行文件&#xff0c;虽然Mac系统上无法直接打开exe文件&#xff0c;但是你可以在Mac电脑上安装双系统或者虚拟机来实现mac电脑上运行exe文件。除了这两种方法之外&#xff0c;你还可以在Mac电脑上使用类虚拟机软件打开exe文件&#xff0c;这三种方法各…

双指针 | 移动零 | 复写零

1.移动零 题目描述&#xff1a; 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 示例&#xff1a; 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]解题思路&#xff1a; right指针一直往后移动&#xff0c;当…

欧洲跨境物流仓库视频监控系统开发的解决方案

中国联通针对仓储物流行业的数字化需求&#xff0c;提供全面的解决方案&#xff0c;特别是在海外仓储领域&#xff0c;我们深谙企业面临的挑战&#xff0c;如预算限制、仓储空间需求以及城郊网络覆盖不足等问题。我们利用自身强大的网络资源和技术实力&#xff0c;为出海仓储企…

redis学习-Hash类型相关命令及特殊情况分析

目录 1. hset KEY key1 value1 key2 value2 ... 2. hget KEY key 3. hgetall KEY 4. hmget KEY key1 key2 ... 5. hkeys KEY 6. hvals KEY 7. hdel KEY key1 key2 ... 8. hlen KEY 9. hexists KEY key 10. hincrby KEY key num 11. hsetnx KEY key value Hash的内部…

实时数仓项目《一》-实时数仓架构

目录 1. 实时数仓与离线数仓 2. 实时数仓需求 3. 架构图 3.1 行为日志处理&#xff1a; 3.2 业务库表处理&#xff1a; 4. 面试题&#xff1a; &#x1f9c0;你们的实时数仓有分层吗&#xff1f; &#x1f9c0;那你们的业务数据呢&#xff1f; &#x1f9c0;那你们的O…

字符分类函数(iscntrl、i是space.....)---c语言

目录 一、定义二、字符分类函数2.1 -iscntrl&#xff08;&#xff09;2.1.1定义2.1.2使用举例 2.2 -isspace&#xff08;&#xff09;2.2.1描述2.2.2使用举例 2.3-isdigit()2.3.1描述2.3.2使用举例 2.4-isxdigit()2.4.1描述 2.5-islower()2.5.1描述2.5.2使用举例 2.6-isupper()…

THM学习笔记—Simple CTF

nmap扫描&#xff0c;发现2222端口很奇怪啊&#xff0c;重新换一种方式扫描2222端口 发现是ssh 先用ftp试试&#xff0c;尝试匿名登录 下载所有文件 发现只有一个ForMitch.txt&#xff0c;告诉我们其账号密码为弱密码&#xff0c;我们猜测Mitch为其用户名&#xff0c;尝试暴力…

MechanicalSoup,一个非常实用的 Python 自动化浏览器交互工具库!

目录 前言 什么是 Python MechanicalSoup 库&#xff1f; 核心功能 使用方法 1. 安装 MechanicalSoup 库 2. 创建 MechanicalSoup 客户端 3. 打开网页并与之交互 实际应用场景 1. 网页自动化测试 2. 网络爬虫与数据提取 3. 网页自动化操作 4. 自动化填写和提交多个表单 5.…

V-JEPA模型,非LLM另外的选择,AGI的未来:迈向Yann LeCun先进机器智能(AMI)愿景的下一步

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

EPICS和Arduino Uno之间基于串行文本协议的控制开发

Arduino Uno的串口服务程序设置如文本的串口通信协议设计以及在Arduino上的应用-CSDN博客中所示。通过在串口上发送约定的文本协议&#xff0c;它实现的功能如下&#xff1a; 实现功能&#xff1a; 读取三路0.0V~5.0V模拟量输入&#xff0c;读取端口A0~A2设置三路0.0V~5.0V的模…

typeof 与 instanceof 区别

文章目录 一、typeof二、instanceof三、区别 一、typeof typeof 操作符返回一个字符串&#xff0c;表示未经计算的操作数的类型 使用方法如下&#xff1a; typeof operand typeof(operand)operand表示对象或原始值的表达式&#xff0c;其类型将被返回 举个例子 typeof 1 /…

K8S之持久化存储

持久化存储 支持的持久化存储类型EmptyDirHostPathNFS 在K8S中部署的应用都是以pod容器的形式运行的&#xff0c;假如部署数据库服务 例如&#xff1a;MySQL、Redis等&#xff0c;需要对产生的数据做备份。如果pod不挂载数据卷&#xff0c;那pod被删除或重启后这些数据会随之消…

Windows server Database 2025 安装 i225/i226 网卡驱动

windows这比坏得很&#xff0c;intel消费级网卡不准在服务器系统上安装。你要说他是异构不支持&#xff1f;他就纯粹恶心人。 之前已经安装过一次&#xff0c;但是今天database预览版一更新&#xff0c;又给我把网卡驱动杀了&#xff0c;气死&#xff0c;写一篇教程。 1.去官网…

SQLite优化实践:数据库设计、索引、查询和分库分表策略

文章目录 一、数据库设计优化1.1 合理选择数据类型1.2 使用NOT NULL约束1.3 使用默认值1.4 避免使用过多的列 二、索引优化2.1 为经常用于查询条件的列创建索引2.2 为经常用于排序和分组的列创建索引2.3 避免过多的索引2.4 使用覆盖索引 三、查询优化3.1 使用预编译语句3.2 优化…

​​SQLiteC/C++接口详细介绍之sqlite3类(十一)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十&#xff09; 下一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十二&#xff09;&#xff08;未发表&#xff09; 33.sq…

C语言学习过程总结(18)——指针(6)

一、数组指针变量 在上一节中我们提到了&#xff0c;指针数组的存放指针的数组&#xff0c;那数组指针变量是什么呢&#xff1f; 显而易见&#xff0c;数组指针变量是指针 同样类比整型指针变量和字符指针变量里面分别存放的是整型变量地址和字符变量地址&#xff0c;我们可以…

Helm的资源安装和基本使用

目录 一.Helm的出现 二.Helm工具 1.部署helm 2.helm可用命令介绍 三.chart 1.添加、查看、删除存储库 2.查找chart、查看chart信息、安装chart等 3.安装chart后产生的release 四.安装mysql举例 1.固定chart安装 2.自定义chart安装 一.Helm的出现 在前面的k8s部署po…