詳細なバックトラッキングアルゴリズム
バックトラッキングの問題を解決することは、実際には決定木のトラバーサルプロセスです。
2種類の決定木トラバーサル:
上記のように、パラメーターtは、現在決定木にあるレイヤーの数です。
サブセットツリー:ナップサック問題など、解ベクトルの条件を満たすサブセットを選択するため。
順列ツリー:完全な順列など、解ベクトルのソート問題の場合、エイトクイーン問題。
順列の問題
問題の説明
繰り返し番号のないシーケンスが与えられた場合、可能なすべての順列を返します。
問題解決の考え
明らかに、この問題は解ベクトルのソート問題であり、配置ツリーをトラバースするテンプレートを直接適用できます。
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<Integer>();
for (int num : nums) {
path.add(num);
}
int n = nums.length;
backtrack(n, path, res, 0);
return res;
}
public void backtrack(int n, List<Integer> path, List<List<Integer>> res, int t) {
if (t >= n) {
//到了最后一层
res.add(new ArrayList<Integer>(path));
}
for (int i = t; i < n; i++) {
Collections.swap(path, t, i);//swap(List list,int i,int j):交换集合中指定元素索引的位置
backtrack(n, path, res, t + 1);
Collections.swap(path, t, i);
}
}
}
時間計算量:O(n!)
空間計算量:O(n)
Nクイーンの問題
問題の説明
nクイーン問題は、n×nチェス盤にnクイーンを配置し、クイーンが互いに攻撃できないようにする方法を研究します。
整数nを与え、n-クイーン問題のすべての異なる解を返します。
各ソリューションには、n-クイーン問題の異なるチェス配置計画が含まれています。ここで、「Q」と「。」はそれぞれクイーンと空の位置を表します。
注意:
1 <= n <= 9
クイーンは互いに攻撃できません。つまり、2つのクイーンを同じ水平、垂直、または対角線上に置くことはできません。
問題解決のアイデア
n * nのチェス盤にはn個のクイーンが必要であり、クイーンは同じ行、同じ列、同じ対角線に配置できないため、各行に1つのクイーンが必要です。次に、列のクイーンの座標が次のようになっているとします。 xi、xi i番目の行の女王がxi番目の列xi∈(0、...、n-1)にあることを意味します。これから、問題は順列問題であることがわかります。解ベクトルの、および順列ツリーのテンプレートを適用できます。実際、この問題はサブセットツリーでも解決できます。
完全配置の問題とは異なり、この問題では、剪定の問題を考慮する必要があります。配置ルールが満たされていない場合は、剪定を行います。
行iのクイーンと行jの
クイーンの場合:1)2つのクイーンが同じ列にない:xi!= xj;
2)2つのクイーンが同じ対角線上にない:| ij |!= | xi- xj |
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> res = new ArrayList<List<String>>();
int row[] = new int[n];//用row存储皇后在列上的排列顺序
backtrack(res,row,n,0);
return res;
}
public void backtrack(List<List<String>> res,int[] row,int n,int t){
//遍历子集树
if(t >= n)
output(res,row,n);
else{
for (int i = 0; i < n; i++){
row[t] = i;
if(legal(row,t))
backtrack(res,row,n, t+1);
}
}
}
public boolean legal(int[] row,int t){
//判断是否为有效的坐标
for(int i=0;i<t;i++){
if(Math.abs(i-t)==Math.abs(row[i]-row[t]) || row[i]==row[t])
return false;
}
return true;
}
public void output(List<List<String>> res,int[] row,int n){
//打印结果
List<String> temp_res = new ArrayList<String>();
for(int i=0;i<n;i++){
String line = "";
for(int j=0;j<n;j++){
if(j == row[i])
line = line + 'Q';
else
line = line + '.';
}
temp_res.add(line);
}
res.add(temp_res);
}
}
時間計算量:O(2 ^ n)
空間計算量:O(n)