力扣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;
	}

}

发布了48 篇原创文章 · 获赞 9 · 访问量 2404

猜你喜欢

转载自blog.csdn.net/jjy19971023/article/details/104567217
今日推荐