力扣46、全排列----回溯法入門----力扣51、N皇后問題

給定一個沒有重複數字的序列,返回其所有可能的全排列。
示例:
輸入: [1,2,3]
輸出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

全排列問題就是將數組裏元素所有可能的排列組合全部整理排列出來。那麼我們排列的話可不可以畫一個排列樹出來?
我們先一條分支畫到頭:1–2--3
這時沒有了,我們回退到1,發現1後面還可以跟3,然後我們得到1–3--2
接下來再回溯到開始,然後2打頭,接着是3打頭。。。
據此我們定義出回溯的算法
通用算法

backtrack(路徑,選擇列表)
{
當路徑長度達到最大時:向列表中添加這一條路徑,return ;

否則
我們從選擇列表中做選擇
backtrack(路徑,選擇列表)
回退做的選擇;

}

據此我們得到全排列的詳細代碼如下:

package medium;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class permuteFirst {
	List<List<Integer>> res = new LinkedList<>();

	public List<List<Integer>> permute(int[] nums) {
		// 記錄路徑
		LinkedList<Integer> track = new LinkedList<Integer>();
		backtrack(nums, track);
		return res;
	}

	/*
	 * 路徑記錄在track中 選擇列表:nums中不存在與track的那些元素 結束條件:nums中所有元素都在track中出現
	 */
	private void backtrack(int[] nums, LinkedList<Integer> track) {

		if (track.size() == nums.length) {
			res.add(new LinkedList(track));
			return;
		}
		for (int i = 0; i < nums.length; i++) {
			// 排除不合法的選擇
			if (track.contains(nums[i]))
				continue;
			// 做選擇
			track.add(nums[i]);
			backtrack(nums, track);

			// 取消選擇
			track.removeLast();

		}
	}
	public static void main(String[] args) {
		// TODO 自動生成的方法存根
	}
}

n 皇后問題研究的是如何將 n 個皇后放置在 n×n 的棋盤上,並且使皇后彼此之間不能相互攻擊。
給定一個整數 n,返回所有不同的 n 皇后問題的解決方案。
每一種解法包含一個明確的 n 皇后問題的棋子放置方案,該方案中 'Q''.' 分別代表了皇后和空位。
示例:
輸入: 4
輸出: [
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],
 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解釋: 4 皇后問題存在兩個不同的解法。

同理N皇后的問題
也如此
我們初始插入一個皇后,然後我們在不違規的情況下插完第一輪皇后,然後回溯一下
代碼如下:

package medium;

import java.util.ArrayList;
import java.util.List;

public class NQueenFirst {
	List<List<String>> res = new ArrayList<>();

	public List<List<String>> solveNQueens(int n) {
		List<String> list = new ArrayList<>();
		for (int i = 0; i < n; i++) {
			list.add(i, string(n, '.'));
		}
		backtrack(list, 0);
		return res;

	}

	private String string(int n, char c) {
		String str = "";
		for (int i = 0; i < n; i++) {
			str = str + c;
		}
		return str;
	}

	private void backtrack(List<String> list, int num) {
		// TODO 自動生成的方法存根
		if (num == list.size()) {
			res.add(new ArrayList(list));
			return;
		}

		for (int i = 0; i < list.size(); i++) {
			// 排除不合法的選擇
			if (!isValid(list, num, i))
				continue;

			StringBuilder s = new StringBuilder(list.get(num));
			s.replace(i, i + 1, "Q");
			String s1 = s.toString();

			list.remove(num);
			list.add(num, s1);
			backtrack(list, num + 1);
			s1 = string(list.size(), '.');
			list.remove(num);
			list.add(num, s1);

		}
	}

	private boolean isValid(List<String> list, int row, int l) {
		// 這一列有無衝突
		for (int i = 0; i < list.size(); i++) {
			if (list.get(i).charAt(l) == 'Q')
				return false;
		}
		// 檢查右上
		for (int i = row - 1, j = l + 1; i >= 0 && j < list.size(); i--, j++) {
			if (list.get(i).charAt(j) == 'Q')
				return false;
		}
		// 檢查左上
		for (int i = row - 1, j = l - 1; i >= 0 && j >= 0; i--, j--) {
			if (list.get(i).charAt(j) == 'Q')
				return false;
		}
		return true;
	}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章