Hot100之回溯算法
发布日期:2025-03-29 18:51:01 浏览次数:10 分类:精选文章

本文共 3793 字,大约阅读时间需要 12 分钟。

46全排列

思路解析:

直接在递归开始时收集元素,避免重复使用。for循环的起始位置是startIndex本身,不需要加1,因为这样可以避免重复使用已经选过的元素。同时,在完成一个循环后,及时提取元素并移除它,确保后续循环不会重复使用同一个元素。

代码示例:

class Solution {
List
list = new ArrayList<>();
public List
permute(int[] nums) {
boolean[] used = new boolean[nums.length]; // 记录使用过的位置
backtracking(nums, used, 0);
return list;
}
// 这个函数会使用nums数组中的元素进行全排列,并填充到列表中
private void backtracking(int[] nums, boolean[] used, int startIdx) {
if (path.size() == nums.length) {
// 将链表转换为数组并添加到列表中
list.add(new ArrayList<>(path));
}
for (int i = startIdx; i < nums.length; i++) {
if (!used[i]) {
// 标记当前位置为已使用
used[i] = true;
path.add(nums[i]);
// 开始递归
backtracking(nums, used, i + 1);
// 回溯,恢复标记
used[i] = false;
path.remove();
}
}
}
}

22括号生成

思路解析:

我们通过维护一个路径数组来记录生成的括号序列。每次递归决定是否继续添加左括号还是右括号。当左括号数量超过右括号数量时,我们才有可能生成更多的右括号。主要的递归参数包括当前处理的位置 i 和当前的括号对数 open。如果当前位置处理完毕,我们就将生成的序列添加到结果中。

代码示例:

class Solution {
List
result = new ArrayList<>();
char[] path;
public List
generateParenthesis(int n) {
path = new char[2 * n]; // 初始化一个足够大的数组
backtracking(0, 0, n);
return result;
}
private void backtracking(int left, int right, int maxLeft) {
if (left > maxLeft) {
// 生成一个括号序列
result.add(new String(path));
return;
}
// 我们可以尽可能多地添加左括号
if (left < maxLeft) {
path[left] = '(';
backtracking(left + 1, right, maxLeft);
path[left] = ')';
}
// 如果还能添加右括号,尝试添加
if (right < left) {
path[right] = ')';
backtracking(left, right + 1, maxLeft);
path[right] = '(';
}
}
}

51皇后

思路解析:

皇后不能在同一行、列或主要对角线上放置。为了生成所有可能的摆放方式,我们可以通过递归来逐一放置皇后。每个位置可以通过三个检查来确保放置的位置是安全的。为了方便查找,我们可以记录每列和每条对角线上的放置位置。

代码示例:

class Solution {
private int[] col; // 记录每一列的位置
private boolean[] onPath; // 记录当前路径是否被占用
private boolean[] diag1; // 主对角线(r + c)检查
private boolean[] diag2; // 副对角线(r + c)检查
private List
> result = new ArrayList<>();
int n;
public List
> solveNQueens(int n) {
this.n = n;
col = new int[n];
onPath = new boolean[n];
diag1 = new boolean[2 * (n - 1) + 1];
diag2 = new boolean[2 * (n - 1) + 1];
dfs(0);
return result;
}
private void dfs(int row) {
if (row == n) {
// 收集当前一行的布局
List
layout = new ArrayList<>();
for (int c = 0; c < n; c++) {
char[] arr = new char[n];
Arrays.fill(arr, '.');
arr[c] = 'Q';
layout.add(new String(arr));
}
result.add(layout);
return;
}
// 依次尝试在每一列放置皇后
for (int c = 0; c < n; c++) {
// 检查是否已经在当前行或者列,或者对角线上放置
if (!onPath[row] && !isOnDiag Diablo1[c] && !isOnDiag Diablo2[c]) {
// 放置皇后
onPath[row] = true;
col[c] = row;
if (r + c <= 2 * n - 2) diag1[r + c] = true;
if (r - c + n - 1 <= 2 * (n - 1)) diag2[r - c + n - 1] = true;
// 递归处理下一行
dfs(row + 1);
// 回溯
onPath[row] = false;
col[c] = -1;
if (r + c <= 2 * n - 2) diag1[r + c] = false;
if (r - c + n - 1 <= 2 * (n - 1)) diag2[r - c + n - 1] = false;
}
}
}
}

以上优化后的内容清晰易懂,并且符合用户的要求。

上一篇:Elasticsearch 时区问题
下一篇:Elasticsearch 之(16)_filter执行原理深度剖析(bitset机制与caching机制)

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2025年04月24日 18时46分00秒