Skip to content

Commit

Permalink
回溯 + BFS
Browse files Browse the repository at this point in the history
  • Loading branch information
nibnait committed Oct 25, 2020
1 parent 9560901 commit 2e3e310
Show file tree
Hide file tree
Showing 17 changed files with 1,014 additions and 3 deletions.
167 changes: 167 additions & 0 deletions src/main/java/algorithm_practice/LeetCode/code000/H051_N皇后.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package algorithm_practice.LeetCode.code000;

import com.google.common.collect.Lists;
import org.junit.Assert;
import org.junit.Test;

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

/*
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
[".Q..",
"...Q",
"Q...",
"..Q."]
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
 
示例:
输入:4
输出:[
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
 
提示:
皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-queens
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class H051_N皇后 {

@Test
public void testCase() {
int n = 4;
List<List<String>> excepted = Lists.newArrayList(
Lists.newArrayList(".Q..", "...Q", "Q...", "..Q."),
Lists.newArrayList(".Q..", "...Q", "Q...", "..Q.")
);

List<List<String>> result = solveNQueens(n);
Assert.assertEquals(excepted, result);
}

public List<List<String>> solveNQueens(int n) {
List<List<String>> result = new ArrayList<>();
List<String> path = new ArrayList<>();

for (int i = 0; i < n; i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < n; j++) {
sb.append(".");
}
path.add(sb.toString());
}

return backTrack(result, path, 0);
}

// 路径:第 row 行之前,都已经放置好 Q 了
// 选择列表:row 这一行的所有列
// 结束条件:row == path.size
private List<List<String>> backTrack(List<List<String>> result, List<String> path, int row) {
if (row == path.size()) {
result.add(newArrayList(path.iterator()));
return result;
}

for (int column = 0; column < path.get(0).length(); column++) {
if (!isValid(path, row, column)) {
continue;
}

path = putQueen(path, row, column);

backTrack(result, path, row + 1);

path = popQueen(path, row, column);

}
return result;
}

private List<String> popQueen(List<String> path, int row, int column) {
return changeQ(path, row, column, '.');
}

private List<String> putQueen(List<String> path, int row, int column) {
return changeQ(path, row, column, 'Q');
}

private List<String> changeQ(List<String> path, int row, int column, char c) {
char[] chars = path.get(row).toCharArray();
chars[column] = c;

List<String> result = new ArrayList<>();
for (int i = 0; i < path.size(); i++) {
if (i == row) {
result.add(String.valueOf(chars));
continue;
}
result.add(path.get(i));
}

return result;
}

private boolean isValid(List<String> path, int row, int column) {
for (int i = 0; i < path.size(); i++) { // 行
String rowList = path.get(i);
for (int j = 0; j < rowList.length(); j++) { // 列

// 第 column 列有 Q
if (j == column && 'Q' == rowList.charAt(j)) {
return false;
}

// 左前右下方向 有 Q
if (i != row && column != j
&& row - i == column - j
&& 'Q' == rowList.charAt(j)) {
return false;
}

// 右上左下方向 有 Q
if (i != row && column != j
&& row - i == j - column
&& 'Q' == rowList.charAt(j)) {
return false;
}
}
}
return true;
}

private List<String> newArrayList(Iterator<String> iterator) {
List<String> result = new ArrayList<>();

while (iterator.hasNext()) {
result.add(iterator.next());
}

return result;
}
}
111 changes: 111 additions & 0 deletions src/main/java/algorithm_practice/LeetCode/code000/M046_全排列.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package algorithm_practice.LeetCode.code000;

import com.google.common.collect.Lists;
import org.junit.Assert;
import org.junit.Test;

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

/*
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class M046_全排列 {

@Test
public void testCase() {
int[] nums = new int[]{1,2,3};
List<List<Integer>> excepted = Lists.newArrayList(
Lists.newArrayList(1,2,3),
Lists.newArrayList(1,3,2),
Lists.newArrayList(2,1,3),
Lists.newArrayList(2,3,1),
Lists.newArrayList(3,1,2),
Lists.newArrayList(3,2,1));
List<List<Integer>> result = permute(nums);
Assert.assertEquals(excepted, result);

}

/*
回溯框架
result = []
def backtrack(路径,选择列表) {
if (满足借宿条件) {
result.add(选择);
}
for 选择 in 选择列表:
if 选择不满足当前选择条件:
continue;
做选择;
backtrace(路径, 选择列表);
撤销选择;
}
*/

public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();

return backTrack(result, path, nums);
}

private List<List<Integer>> backTrack(List<List<Integer>> result, List<Integer> path, int[]nums) {
if (path.size() == nums.length) {
result.add(newArrayList(path.iterator()));
return result;
}

for (int i = 0; i < nums.length; i++) {
int num = nums[i];
if (path.contains(num)) {
continue;
}

path.add(num);

backTrack(result, path, nums);

path.remove(path.size()-1);
}

return result;
}

private List<Integer> newArrayList(Iterator<Integer> iterator) {
ArrayList list = new ArrayList<>();

while(iterator.hasNext()) {
list.add(iterator.next());
}

return list;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package algorithm_practice.LeetCode.code000;

import com.google.common.collect.Lists;
import org.junit.Assert;
import org.junit.Test;

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

/*
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class M047_全排列2 {

@Test
public void testCase() {
int[] nums = new int[]{1,1,2};
List<List<Integer>> excepted = Lists.newArrayList(
Lists.newArrayList(1,1,2),
Lists.newArrayList(1,2,1),
Lists.newArrayList(2,1,1));
List<List<Integer>> result = permuteUnique(nums);
Assert.assertEquals(excepted, result);


}

public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
boolean[] used = new boolean[nums.length];

return backTrack(result, path, nums, used);
}

private List<List<Integer>> backTrack(List<List<Integer>> result, List<Integer> path, int[] nums, boolean[] used) {
if (path.size() == nums.length) {
if (!result.contains(path)) {
result.add(newArrayList(path.iterator()));
}
return result;
}

for (int i = 0; i < nums.length; i++) {
if (used[i]) {
continue;
}

used[i] = true;
path.add(nums[i]);

backTrack(result, path, nums, used);

used[i] = false;
path.remove(path.size() - 1);
}

return result;
}

private List<Integer> newArrayList(Iterator<Integer> iterator) {
List<Integer> result = new ArrayList<>();
while (iterator.hasNext()) {
result.add(iterator.next());
}
return result;
}
}
Loading

0 comments on commit 2e3e310

Please sign in to comment.