[41]バックトラッキング方法-完全な順列| Nクイーンの問題(LC 46 | 51)

詳細なバックトラッキングアルゴリズム

バックトラッキングの問題を解決することは、実際には決定木のトラバーサルプロセスです。

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)

おすすめ

転載: blog.csdn.net/qq_43424037/article/details/114293727