采用DFS,顺序有关。
(一)Permutations
https://leetcode.com/problems/permutations/description/
题目:给定一个无重复元素的数组,要求返回所有的排列组合;
解答:与其他dfs类似,此外使用了hashset以避免组合元素的重复;
第一次犯错:直接使用将hashset转化为arraylist的方式添加到结果。不可以这样操作,因为hashset的输出不是按照元素添加顺序!
代码:
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if (nums == null || nums.length == 0) {
return res;
}
List<Integer> singleList = new ArrayList<>();
Set<Integer> set = new HashSet<>();
dfsMethod(res, nums, set, singleList);
return res;
}
private void dfsMethod(List<List<Integer>> list, int[] nums, Set<Integer> set, List<Integer> singleList) {
if (set.size() == nums.length) {
list.add(new ArrayList<Integer>(singleList));
}
for (int i = 0; i < nums.length; i++) {
if (set.contains(nums[i])) {
continue;
}
set.add(nums[i]);
singleList.add(nums[i]);
dfsMethod(list, nums, set, singleList);
singleList.remove(singleList.size() - 1);
set.remove(nums[i]);
}
}
}
(二)Permutations II
https://leetcode.com/problems/permutations-ii/description/
题目:给定一个有重复元素的数组,要求返回所有的排列组合;
解答:不使用set,用一个visited[]数组来存储访问过的元素位置:1表示该位置元素已经访问完毕,0表示尚未访问该位置元素;
第一次犯错:数组初始化值不能一步到位,需要先建立一个长度固定的空数组,再写一个循环,依次给数组元素赋值;
代码:
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if (nums == null || nums.length == 0) {
return res;
}
List<Integer> singleList = new ArrayList<>();
int visited[] = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
visited[i] = 0;
}
Arrays.sort(nums);
dfsMethod(res, nums, visited, singleList);
return res;
}
private void dfsMethod(List<List<Integer>> list, int[] nums, int[] visited, List<Integer> singleList) {
if (singleList.size() == nums.length) {
list.add(new ArrayList<Integer>(singleList));
}
for (int i = 0; i < nums.length; i++) {
if (visited[i] == 1 || (i > 0 && nums[i] == nums[i - 1] && visited[i - 1] == 1)) {
continue;
}
singleList.add(nums[i]);
visited[i] = 1;
dfsMethod(list, nums, visited, singleList);
singleList.remove(singleList.size() - 1);
visited[i] = 0;
}
}
}
(三)N-Queens
https://leetcode.com/problems/n-queens/description/
题目:在n*n的棋盘上放n个皇后,要求返回所有皇后不冲突的组合。(若两个皇后处在同一行或者同一列或者对角线上,则冲突);
解答:将整个棋盘坐标化,从第一行开始(y = 0),依次遍历0 ~ n列(x),判断是否与之前存储的Queen冲突,若不冲突则更新usedCols并将其放入栈中。
技巧:1.将Queen所在列存储在列表中,列表的index代表纵坐标,index所在位置存储的值为横坐标;
2.可以先不将棋盘用string表示出来,当Queen所在列存储完全后再统一画(参见drawBoard函数)。
代码:
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> res = new ArrayList<>();
if (n <= 0) {
return res;
}
List<Integer> usedCols = new ArrayList<>();
dfsMethod(res, n, usedCols);
return res;
}
private void dfsMethod(List<List<String>> list, int n, List<Integer> usedCols) {
if (usedCols.size() == n) {
list.add(drawBoard(usedCols));
}
for (int i = 0; i < n; i++) {
if (!isValid(n, usedCols, i, usedCols.size())) {
continue;
} else {
usedCols.add(i);
dfsMethod(list, n, usedCols);
usedCols.remove(usedCols.size() - 1);
}
}
}
private List<String> drawBoard(List<Integer> usedCols) {
List<String> res = new ArrayList<>();
for (int i = 0; i < usedCols.size(); i++) {
String s = "";
for (int j = 0; j < usedCols.size(); j++) {
if (usedCols.get(i) == j) {
s += "Q";
} else {
s += ".";
}
}
res.add(s);
}
return res;
}
private Boolean isValid(int n, List<Integer> usedCols, int x, int y) {
for (int i = 0; i < usedCols.size(); i++) {
//check columns
if (usedCols.get(i) == x) {
return false;
}
//check diagnols
if (x -usedCols.get(i) == y - i) {
return false;
}
if (usedCols.get(i) - x == y - i) {
return false;
}
}
return true;
}
}