- 博客(136)
- 收藏
- 关注
原创 代码随想录|动态规划|31打家劫舍III
之前打家劫舍的问题,我们最后求的是dp[nums.size()-1]也就是偷最后一个房子的最大金钱,那么这里按照后序遍历,可以把root根节点看作是最后的房子。这里不可以再用i去代表每一个状态的下标了,因为是二叉树,不是数组,二叉树有自己的遍历方式。树形dp,dp数组的形式真的没想到还能这样子写,归根还是在于数组跟树的遍历区别,树的遍历一定是那3种遍历顺序的,你用下标i根本无法表示。父节点一定和子节点连着的,所以相邻的节点不可以都偷,只能隔着偷。通过递归左节点,得到左节点偷与不偷的金钱。
2025-04-06 12:56:22
352
原创 代码随想录|动态规划|30打家劫舍II
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。当然情况2、3实际上包含了情况1,比如情况2,我只是考虑了首元素,没说一定要选啊。输入:nums = [1,2,3,1]输入:nums = [2,3,2]
2025-04-06 12:11:37
282
原创 代码随想录|动态规划|29打家劫舍
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);(1)dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i]如果不偷第i房间,那么dp[i] = dp[i - 1],即考虑i-1房,((3)递推公式有i-2和i-1,所以初始化应该考虑dp[0]和dp[1]。
2025-04-06 12:09:51
268
原创 代码随想录|动态规划|26单词拆分
(2)如果确定dp[j] 是true,且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。(1)dp[i]: 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词。(4)dp[0]一定为true,不然后面根据递推公式会一直为false。从小到大逐渐找s的子串,看子串是不是数组里面的元素。你可以假设字典中没有重复的单词。
2025-04-04 16:30:48
202
原创 代码随想录|动态规划|24完全平方数
(3)dp[0]表示 和为0的完全平方数的最小数量,本来写的是1,但是题目要求n>=1,所以这里j=0只是为了递推公式好写,实际上是dp[0]=0。(1)dp[j]:填满容量为j的背包,需要的最少物品个数。(和为j的完全平方数的最小个数)物品:i从0开始,最大满足i*i<=n。(4)求个数,不考虑遍历的顺序。转换成背包问题之后就很好写了。原问题转换为完全背包问题。背包容量:n,需要填满。物品的容量:i*i。
2025-04-04 15:35:33
247
原创 代码随想录|动态规划|23零钱兑换
(2)如果包含coins[i],凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j]。考虑到递推公式的特性,dp[j]必须初始化为一个最大的数,否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。递推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);所以下标非0的元素都是应该是最大值。
2025-04-04 15:14:19
242
原创 代码随想录|动态规划|21组合总和IV
所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1)给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。递推公式为 dp[j] += dp[j-nums[i]];排列强调排序顺序,所以先遍历背包,再遍历物品。物品就是nums数组的每一个元素nums[i]这里跟上面那道题的区别在于 “排列!请注意,顺序不同的序列被视作不同的组合。物品对应的容量也是nums[i]
2025-04-03 20:38:25
175
原创 代码随想录|动态规划|19零钱兑换II
(1)dp[i][j]:使用 下标为[0, i]的coins[i]能够凑满j(包括j)这么大容量的包,有dp[i][j]种组合方法。那么就是先把1加入计算,然后再把5加入计算,得到的方法数量只有{1, 5}这种情况。背包容量的每一个值,都是经过 1 和 5 的计算,包含了{1, 5} 和 {5, 1}两种情况。第一列:背包容量为0,就是啥也装不了,就一种方法,即dp[i][0]=1.假设:coins[0] = 1,coins[1] = 5。(1)dp[j]:凑成总金额j的货币组合数为dp[j]
2025-04-03 20:27:40
959
原创 代码随想录|动态规划|18完全背包理论基础
背包空出物品i的容量后,背包容量为j - weight[i],dp[i][j - weight[i]] 为背包容量为j - weight[i]且不放物品i的最大价值,那么dp[i][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值。递推公式: dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]);现在:剩下的容量还可以再放物品1,dp[1][4-nums[1]]+values[1];
2025-04-03 19:58:51
854
原创 代码随想录|动态规划|17一和零
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4。其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"}。输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3。(1)dp[i][j]:最多有i个0,j个1的strs的最大子集的大小为dp[i][j](3)根据定义,最多有0个0,0个1,这就根本没有子集,所以dp[0][0]=0。
2025-04-03 16:35:36
445
原创 代码随想录|动态规划|16目标和
此时装满背包容量为1 有 dp[1][1] 种方法,即: 不放物品2,背包容量为1,只考虑物品 0 和 物品 1,有 dp[1][1] 种方法。第一行: 只放物品0,把容量为j的背包填满,只有nums[0]==j的情况,才可以恰好把背包填满,其余情况要么填不满,要么填不够。: 先空出物品i的容量,背包容量为(j - 物品i容量),放满背包有 dp[i - 1][j - 物品i容量] 种方法。(1)dp[i][j]:使用下标为[0, i]的nums[i]能够装满j这么大容量的包,有dp[i][j]种方法。
2025-04-02 17:01:58
1599
原创 代码随想录|动态规划|14最后一块石头的重量II
target=sum/2是向下取整的,也就是说dp[target]≤sum/2,所以sum-dp[j]≥dp[j],所以最终的差值为。假设石头的重量分别为 x 和 y,且 x <= y。(2)01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);= y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。(1)dp[j]表示容量为j的背包,最多可以背最大重量为dp[j]。如果 x == y,那么两块石头都会被完全粉碎;
2025-04-02 15:39:53
439
原创 代码随想录|动态规划|13分割等和子集
(2)01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);(1)01背包中,dp[j] 表示: 容量(所能装的重量)为j的背包,所背的物品价值最大可以为dp[j]。所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])这里target=sum/2,背包最大重量为target,背包最大能装dp[target]这里的weight[i]就是nums[i],value[i]就是nums[i]。
2025-04-02 15:24:24
364
原创 代码随想录|动态规划|12“0-1”背包问题二
二维数组的时候,递推公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);dp[2] = dp[2 - weight[0]] + value[0] = 15 (dp数组已经都初始化为0)dp[i][j]都是通过上一层即dp[i - 1][j]计算而来,本层的dp[i][j]并不会被覆盖。(1)在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。如果正序遍历(这里都是i=0的情况下)
2025-04-02 15:07:51
356
原创 代码随想录|动态规划|11“0-1”背包问题一
背包容量为 3,上一行同一状态,背包只能放物品0,这次也可以选择物品1了,背包可以放物品1 或者 物品0,物品1价值更大,背包里的价值为20。背包容量为 4,上一行同一状态,背包只能放物品0,这次也可以选择物品1了,背包可以放下物品0 和 物品1,背包价值为35。首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
2025-04-01 17:54:00
657
原创 代码随想录|动态规划|09不同的二叉搜索树
(2)dp[i] += dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量]给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?(5)自己画图画到3就得了,后面的太复杂,直接给出答案。(1)1到i为节点组成的二叉搜索树的个数为dp[i]。(3)空节点也是单独的一棵树,dp[0] = 1。(4)i从1到n,j从1到i,分析过程已经说了。1为头节点:左子树0节点*右子树2节点。2为头节点:左子树1节点*右子树1节点。3为头节点:左子树2节点*右子树0节点。
2025-03-31 15:04:26
436
原创 代码随想录|动态规划|08整数拆分
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。返回你可以获得的最大乘积。正整数拆分,应该是尽可能拆分成比较接近的数,比如9拆成3*3*3,因为距离相近的数相乘更大。(3)按照题意来看,0和1是无法进行初始化的,所以初始化dp[2] = 1。这个递推公式真的不好想,其实j的范围还可以再缩小,等二刷的时候我再加。因为dp[i - j]里面已经包括了j的拆分情况,没必要重复拆分。(1)dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。这里为什么j不拆分?
2025-03-31 14:47:10
341
原创 代码随想录|动态规划|07不同路径II
(2)每个点的路径还是只可从上面或者左边得到,即dp[i][j] = dp[i - 1][j] + dp[i][j - 1]。(1)dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径.但是这里要考虑障碍物的情况,如果这个点有障碍物,那么其实是无法到达这个点,也就是0。(4) 遍历顺序还是跟以前一样的,只是在遍历的过程中加了一个障碍物的判断条件。(3)如果障碍物出现在第一行或者第一列,那么障碍物往后的点全都无法达到。网格中的障碍物和空位置分别用 1 和 0 来表示。
2025-03-31 14:26:14
328
原创 代码随想录|动态规划|06不同路径
(2)dp[i][j]只能从dp[i-1][j]和dp[i][j-1]获取,所以dp[i][j] = dp[i - 1][j] + dp[i][j - 1],这里的逻辑有点像前几天做的爬楼梯那个题,只能从上一个或者上上个楼梯爬过来。(4)每个网格的取值要看它的左边和它的上边,所以i遍历每一行,j遍历每一列,用两层for循环遍历就行了,不过起始位置是i=1和j=1。(1)dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。有点像小学里面的一些画图题,递归公式不难想。
2025-03-31 12:22:44
320
原创 代码随想录|回溯算法|10复原IP地址
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效的 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效的 IP 地址。此外这里的else执行的是break,因为在当前层,只要前面的分割不合法,那么后面无论怎么分割都是不合法的,所以break直接结束本层循环。但是在判断合法之后,需要给当前区间的后面插入一个'.',此时区间的长度+1,所以在回溯的时候不是i+1而是i+2!
2025-03-30 20:57:31
612
原创 代码随想录|回溯算法|09分割回文串
子串的范围是[startIndex,i],然后使用isValid来判断是否为回文子串,如果是回文,就加入到path,path用来记录切割过的回文子串。切割问题跟组合问题很像,切割也要求不可以重复切割,所以需要用一个startIndex来指定每次切割的起始位置。示例: 输入: "aab" 输出: [ ["aa","b"], ["a","a","b"] ]子串str的获取方式用的是substr函数,获取当前这一段的字符串。给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
2025-03-30 19:26:27
500
原创 代码随想录|动态规划|04使用最小花费爬楼梯
一定是选最小的,所以dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);(5)举例cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]dp[i - 1] 跳到 dp[i] 需要花费 dp[i - 1] + cost[i - 1]。dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]。- 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
2025-03-29 16:45:24
414
原创 代码随想录|动态规划|03爬楼梯
如何把这个题转换成斐波那契数列,需要分析到达第i层的两种情况是互斥的,所以他们的走法加起来就是到达第i层的走法。(3)题目说n是正整数,所以i从1开始的,dp[1]=1,dp[2]=2。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?并且dp[i-1]和dp[i-2]的路径是没有重复的,它们是互斥的。所以dp[i]=dp[i-1]+dp[i-2]!(1)爬到第i层楼梯,有dp[i]种方法。注意:给定 n 是一个正整数。dp[i-1]走一步。dp[i-2]走两步。
2025-03-29 15:36:43
368
原创 代码随想录|动态规划|02斐波那契数列
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列。也就是: F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1 给你n ,请计算 F(n)。我一开始没有提前加边界条件,就会在n=0时候报错,因为后面直接用了dp[1]超出了索引的范围。(4)根据(2)里面的递归公式,要求i≥2,所以从2开始遍历。(3)题目给了,dp[0]=0,dp[1]=1。(1)dp[i]表示第i个数,i是从0开始的。兔子数列,就是前两个数相加。
2025-03-29 15:10:50
428
原创 代码随想录|动态规划|01动态规划理论基础
需要注意的是,先确定递推公式然后再去确定初始条件,动态规划的初始条件有点特殊,不仅仅是dp[0],可能还要考虑 dp[1]、dp[2]等等。调试的话,尽量在IDE打印dp数组,后面的笔记我尽量用ACM格式的代码。
2025-03-29 14:55:14
112
原创 代码随想录|贪心算法|22单调递增的数字
一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。(2)标记flag不可以初始化为0,如果数字原本就是递增的,那么第二个for循环会直接把数字的每个位全部变成9。给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增。所以我们在遍历的时候,i从nums.size()-1开始,往前遍历。
2025-03-28 15:04:14
395
原创 代码随想录|贪心算法|20合并区间
这里就是要找重叠区间,而前面射气球那些题是要去除重叠区间,所以是找左区间还是右区间,要看清楚题意。有区别的就是,以前用的是min,现在要用max,找到两个重叠区间的最右边。重叠问题都是先排序再判断重叠,这里还是先按照左区间从小到大排序。更新右区间,直接在result.back()上面更新。可以看出重叠的区间,左边界不用管,只更新右边界就行。给出一个区间的集合,请合并所有重叠的区间。不重叠的区间,就加入到result。
2025-03-28 14:13:13
287
原创 代码随想录|贪心算法|19划分字母区间
我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。使用数组(数组也算哈希表)hash来记录,映射字符到索引,而且用hash[S[i] - 'a']这种相对索引,避免了ASCII。如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点。如果当前的i已经到了当前区间的最远右边界,就开始分割,然后把前面的这一段区间长度计算一下,加入到我们的结果里面。如何找字符出现的最远下标,首先肯定是在遍历中操作,但是这里涉及到字符跟索引的对应关系?hash的使用,对于这种字符的问题。
2025-03-28 11:39:56
347
原创 代码随想录|贪心算法|18无重叠区间
也可以直接在上个题的代码基础上直接修改,这里的问题是求重叠区间个数,而上题弓箭的数量就是非交叉区间的数量,我们用总区间个数减去弓箭数量,就是需要移除区间的数量。注意: 可以认为区间的终点总是大于它的起点。区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。重叠区间的问题,核心还是在min这一块,然后每道题的题目需要仔细看一下,端点重叠到底算不算区间重叠?给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
2025-03-28 11:04:58
287
原创 代码随想录|贪心算法|17用最少数量的箭引爆气球
在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。注意题目中说的是:满足 xstart ≤ x ≤ xend,则该气球会被引爆。从天上垂直丢下一个弓箭,要保证用到的弓箭数量最少,那就要让一个弓箭能射穿更多气球(更多区间),那就是重叠的区间。
2025-03-28 10:43:14
650
原创 代码随想录|贪心算法|14根据身高重建队列
返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。从左到右,身高是降序排列,这个是定死的,跟发糖果那个题一样,要考虑两种维度,我们不能放在一起考虑,而是先考虑一个,然后再考虑另外一个。所以这里先按照身高进行降序排列,如果身高一样怎么办,那就把k更大的放在后面,因为题意是这么说的。需要考虑多个维度的贪心问题,就一步步来,处理完一个维度,在考虑其他的。然后我们再考虑k,把k的那个数组插入到索引为k的位置。
2025-03-26 15:17:35
534
原创 代码随想录|贪心算法|13柠檬水找零
每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。如果你能给每位顾客正确找零,返回 true ,否则返回 false。在柠檬水摊上,每一杯柠檬水的售价为 5 美元。如果上面两个找法都不行,返回false。需要找5元,此时手上至少得有一张5元。收钱只有3种情况,5、10、20.如果没有5元,返回false。找一个10元+一个5元。
2025-03-26 15:00:09
449
原创 代码随想录|贪心算法|12分糖果
首先可以确定每个人都有一个糖果,然后就是相邻之间进行比较呗,谁大谁的糖果就增加,但是每个人(除了两边的)都要和两边的进行比较,如果比较完左边的,然后比较右边的,不太好确定情况。这在leetcode上是一道困难的题目,其难点就在于贪心的策略,如果在考虑局部的时候想两边兼顾,就会顾此失彼。老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。这样从局部最优推出了全局最优,即:相邻的孩子中,评分高的孩子获得更多的糖果。局部最优:只要右边的比左边分数高,那么糖果就+1。
2025-03-26 14:37:36
409
原创 代码随想录|贪心算法|11加油站
i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。局部最优:当前累加rest[i]的和curSum一旦小于0,起始位置至少是i+1,因为从i之前开始一定不行。首先,如果总油量大于等于总消耗,就一定可以跑完一圈,说明各个站点的剩油量rest[i]加起来一定是≥0的。怎么理解起来这么简单?全局最优:找到可以跑一圈的起始位置。
2025-03-26 09:46:15
263
原创 代码随想录|贪心算法|09K次取反后最大化的数组和
题目题目给你一个整数数组nums和一个整数kinums[i]-nums[i]重复这个过程恰好k次。可以多次选择同一个下标i。以这种方式修改数组后,返回数组。5选择下标 1 ,nums 变为 [4,-2,3]。6选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2]。13选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4]。思路。
2025-03-25 15:01:21
980
原创 代码随想录|贪心算法|08跳跃游戏II
这个范围内最少步数一定可以跳到,不用管具体是怎么跳的,不纠结于一步究竟跳一个单位还是两个单位。这里的做法有点类似于双指针法,定义两个覆盖范围:当前的最大覆盖范围和下一步的最大范围。局部最优:当前可移动距离尽可能多走,如果还没到终点,步数加一。整体最优:一步尽可能夺走,争取在最少的步数内走到终点。你的目标是使用最少的跳跃次数到达数组的最后一个位置。给定一个非负整数数组,你最初位于数组的第一个位置。数组中的每个元素代表你在该位置可以跳跃的最大长度。说明: 假设你总是可以到达数组的最后一个位置。
2025-03-25 14:21:09
466
原创 代码随想录|贪心算法|07跳跃游戏
无法确定每次具体要跳多少步,但是可以保证跳跃的范围是多少,只要跳跃的范围包括了最后一个元素,就说明可以到达终点。能否到达,主要是看覆盖范围,不一定要具体求每次走多少步,只要能走到最后就行。如果 cover 大于等于了终点下标,直接 return true。整体最优:最后得到整体最大覆盖范围,看是否能到达终点。给定一个非负整数数组,你最初位于数组的第一个位置。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个位置。局部最优:每次取最大跳跃范围。
2025-03-25 11:46:14
679
原创 代码随想录|贪心算法|06买卖股票的最佳时机II
相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。也就是说第二天就要把前一天的给卖了,如果可以赚钱那就加入总利润,不能赚钱的话,就把当天的卖掉,第二天重新买,这个过程利润为0。假如第 0 天买入,第 3 天卖出,那么利润为:prices[3] - prices[0]。我觉得利润拆分没有自己想的那样直观,就是“能赚就赚,不能赚就保持不亏不赚”。局部最优:每次只收集正利润,其余的就是0利润。
2025-03-25 11:35:26
339
原创 代码随想录|回溯算法|16全排列II
跟上一题的区别在于nums里面有重复的元素,那么同一树层上的元素不可以重复取,同一树枝上的元素(实际是元素值相等的不同元素)可以重复取,这就是used数组的正常情况了,那这里跟组合/子集的区别就是startIndex了,排列不需要startIndex!因为在上道题里面nums没有重复的,所以就没有加if(used[i]==false)这个判断条件,这道题如果不加的话,树枝的元素一直被重复使用了。给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
2025-03-24 16:31:02
583
原创 代码随想录|回溯算法|15全排列
(2)这里用了used数组,但是我们却没有sort,因为这里的used数组并不是用来处理树层重复的,而是为了记录同一树枝上已经使用过的元素。比如先取2,之后1、3都要取,说明for循环i从0开始,used数组是用来告诉我们2已经取了。(3)排列我们需要取所有的元素,也就是说要搜索集合{1,2,3}的所有元素。(2)收集叶子节点,就是path.size==nums.size。给定一个 没有重复 数字的序列,返回其所有可能的全排列。(1)排列从0开始搜索,不需要startIndex。
2025-03-24 16:05:16
381
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人