class Solution {
List> resList = new ArrayList>();
List res = new ArrayList<>();
public List> findSubsequences(int[] nums) {
dfs(nums, 0);
return resList;
}
private void dfs(int[] nums,int index){
Set uset = new HashSet<>();
if (res.size() >= 2) {
resList.add(new ArrayList<>(res));
}
for(int i = index;i < nums.length;i++){
if((res.isEmpty() || nums[i] >= res.get(res.size()-1)) && !uset.contains(nums[i])){
res.add(nums[i]);
uset.add(nums[i]);
dfs(nums,i+1);
res.remove(res.size()-1);
}
}
}
}
这段代码实现了寻找数组中所有递增子序列的功能,其中子序列的长度至少为 2。下面我来分析其工作原理:
采用深度优先搜索 (DFS) 结合回溯法,通过递归的方式探索所有可能的递增子序列,并使用集合进行去重处理,确保结果中没有重复的子序列。
代码解析
成员变量:
resList
:用于存储所有符合条件的递增子序列res
:作为临时容器,存储当前正在构建的子序列主方法 findSubsequences
:
DFS 递归方法:
index
:当前递归开始遍历的数组索引uset
:用于记录本层递归中已经使用过的元素,防止同一层出现重复选择递归终止与收集结果:
res
的长度大于等于 2 时,将其加入结果集resList
循环与选择逻辑:
index
开始遍历数组,确保子序列元素的相对顺序res.isEmpty()
)!uset.contains(nums[i])
,用于去重)回溯操作:
res
和uset
i+1
)res
中最后一个元素,实现回溯,尝试其他可能的选择去重逻辑说明
uset
在每一层递归中都会重新创建,仅作用于当前层的元素选择。这确保了:
[7,7]
这样的有效子序列)例如,对于数组[4,7,7]
,代码会正确生成[4,7]
和[4,7,7]
,但不会因为两个 7 而生成重复的[4,7]
。
这段代码时间复杂度为 O (2^n)(最坏情况下需要探索所有可能的子序列),空间复杂度为 O (n)(递归栈深度和临时存储的子序列长度)。
class Solution {
List> resList = new ArrayList>();
List res = new ArrayList<>();
boolean[] used;
public List> permute(int[] nums) {
int len = nums.length;
if(len == 0) return resList;
used = new boolean[len];
dfs(nums);
return resList;
}
private void dfs(int[] nums){
if(res.size() == nums.length) {
resList.add(new ArrayList<>(res));
return ;
}
for(int i = 0;i
这段代码实现了数组全排列的功能,能够生成给定数组中所有元素的所有可能排列组合。下面我来分析其工作原理:
采用深度优先搜索 (DFS) 结合回溯法,通过递归的方式探索所有可能的元素排列,使用一个布尔类型的数组记录元素是否已被使用,确保每个元素在每个排列中只出现一次。
代码解析
成员变量:
resList
:用于存储所有可能的排列结果res
:作为临时容器,存储当前正在构建的排列used
:布尔数组,标记对应索引的元素是否已被使用主方法 permute
:
used
数组,用于标记元素使用状态DFS 递归方法:
res
的长度等于数组长度时,表示已构建出一个完整排列resList
并返回循环与选择逻辑:
used[i]
为true
),则跳过该元素dfs
继续构建排列的下一个位置工作流程示例
以数组[1,2,3]
为例,代码的执行流程如下:
res
为空,used
全为false
res
变为[1]
res
变为[1,2]
res
变为[1,2,3]
,达到数组长度,加入结果集这段代码的时间复杂度为 O (n×n!),其中 n 是数组长度,需要生成 n! 个排列,每个排列需要 O (n) 的时间来复制。空间复杂度为 O (n),主要用于递归栈和存储当前排列。
class Solution {
List> resList = new ArrayList>();
List res = new ArrayList<>();
boolean[] used;
public List> permuteUnique(int[] nums) {
int len = nums.length;
if(len == 0) return resList;
Arrays.sort(nums);
used = new boolean[len];
dfs(nums);
return resList;
}
public void dfs(int[] nums){
if(res.size() == nums.length){
resList.add(new ArrayList<>(res));
return ;
}
for(int i = 0;i 0 && nums[i] == nums[i-1] && used[i-1]==false)continue;
if(!used[i] ){
used[i] = true;
res.add(nums[i]);
dfs(nums);
res.remove(res.size()-1);
used[i] = false;
}else continue;
}
}
}
这段代码实现了求含重复元素数组的所有不重复全排列的功能。与普通全排列不同,它通过特定的去重逻辑确保生成的排列没有重复项。下面我来分析其工作原理:
采用深度优先搜索 (DFS) 结合回溯法,同时通过排序和精心设计的条件判断来去除重复排列。关键在于对相同元素的处理 —— 确保相同元素在排列中保持固定的相对顺序,从而避免生成重复排列。
代码解析
成员变量:
resList
:用于存储所有不重复的排列结果res
:作为临时容器,存储当前正在构建的排列used
:布尔数组,标记对应索引的元素是否已被使用主方法 permuteUnique
:
used
数组,启动 DFS 搜索DFS 递归方法:
res
的长度等于数组长度时,表示已构建出一个完整排列resList
并返回循环与去重逻辑:
if(i > 0 && nums[i] == nums[i-1] && used[i-1]==false)continue
dfs
继续构建排列的下一个位置去重逻辑说明
去重的关键在于对相同元素的处理策略:
例如,对于数组[1,1,2]
:
[1,1,2]
[1,1,2]
排列这段代码的时间复杂度为 O (n×n!),空间复杂度为 O (n)(用于递归栈、存储当前排列和标记数组)。排序操作额外增加了 O (n log n) 的时间复杂度,但不影响整体数量级。
class Solution {
List> res = new ArrayList<>();
public List> solveNQueens(int n) {
char[][] chessboard = new char[n][n];
for (char[] c : chessboard) {
Arrays.fill(c, '.');
}
dfs(n,0,chessboard);
return res;
}
private void dfs(int n,int row,char[][] chessboard){
if(n == row){
res.add(toList(chessboard));
return;
}
for(int i = 0;i toList(char[][] chessboard){
List list = new ArrayList<>();
for (char[] c : chessboard) {
list.add(String.copyValueOf(c));
}
return list;
}
private boolean isValid(int row,int col,int n,char[][] chessboard){
// 竖着
for(int i = 0;i=0 && j >= 0;i --,j--){
if(chessboard[i][j] == 'Q') return false;
}
for(int i = row -1,j = col + 1;i>=0 && j<=n-1;i--,j++){
if(chessboard[i][j] == 'Q') return false;
}
return true;
}
}
这段代码实现了经典的 N 皇后问题求解,能够的是回溯算法来找出所有可能的摆放方案,使得每个方案中 N 个皇后彼此不会相互攻击(即不在同一行、同一列或同一斜线上)。
N 皇后问题的核心挑战是在 N×N 的棋盘上放置 N 个皇后,使它们不能互相攻击。代码采用深度优先搜索 (DFS) 结合回溯法,逐行尝试放置皇后,通过有效性检测确保放置的皇后是安全的。
代码解析
成员变量:
res
:用于存储所有有效的皇后后摆放方案,每个方案表示为字符串列表主方法 solveNQueens
:
DFS 递归方法:
row
:当前正在处理的行chessboard
:当前的棋盘状态n == row
),表示已找到一个有效解辅助方法 toList
:
有效性检查方法 isValid
:
(row, col)
位置放置皇后后是否安全算法执行流程
时间和空间复杂度
这段代码高效地解决了 N 皇后问题,通过逐行处理和有效的剪枝(只在安全位置放置皇后)避免了不必要的搜索,是回溯算法的经典应用。