子集
lintcode-17
解法1:组合型DFS
public class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> subsets = new ArrayList<List<Integer>>();
Arrays.sort(nums);
subsetHelper(nums, 0, new ArrayList<Integer>(), subsets);
return subsets;
}
public void subsetHelper(int[] a, int start, List<Integer> subset, List<List<Integer>> subsets) {
subsets.add(new ArrayList<Integer>(subset));
for (int i = start; i < a.length; ++i) {
subset.add(a[i]);
subsetHelper(a, i + 1, subset, subsets);
subset.remove(subset.size() - 1);
}
}
}
解法2:BFS
public class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> subsets = new ArrayList<List<Integer>>();
Arrays.sort(nums);
Queue<List<Integer>> queue = new ArrayDeque<List<Integer>>();
queue.offer(new ArrayList<Integer>());
while (!queue.isEmpty()) {
List<Integer> subset = queue.poll();
subsets.add(new ArrayList<Integer>(subset));
for (int i = 0; i < nums.length; ++i) {
if (subset.size() > 0 && subset.get(subset.size() - 1) >= nums[i]) {
continue;
}
subset.add(nums[i]);
queue.offer(new ArrayList<Integer>(subset));
subset.remove(subset.size() - 1);
}
}
return subsets;
}
}
相似题目:子集II
lintcode-18
解法1:组合型DFS+剪枝
public class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> subsets = new ArrayList<List<Integer>>();
Arrays.sort(nums);
subsetHelper(nums, 0, new ArrayList<Integer>(), subsets);
return subsets;
}
public void subsetHelper(int[] a, int start, List<Integer> subset, List<List<Integer>> subsets) {
subsets.add(new ArrayList<Integer>(subset));
memo.add(serialize(subset));
for (int i = start; i < a.length; ++i) {
if (i > start && a[i] == a[i - 1]) {
continue;
}
subset.add(a[i]);
subsetHelper(a, i + 1, subset, subsets);
subset.remove(subset.size() - 1);
}
}
}
解法2:BFS
public class Solution {
class Struct {
private List<Integer> subset;
private int end;
public Struct(List<Integer> subset, int end) {
this.subset = subset;
this.end = end;
}
}
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> subsets = new ArrayList<List<Integer>>();
Arrays.sort(nums);
Queue<Struct> queue = new ArrayDeque<Struct>();
queue.offer(new Struct(new ArrayList<Integer>(), -1));
while (!queue.isEmpty()) {
List<Integer> subset = queue.peek().subset;
int end = queue.poll().end;
subsets.add(new ArrayList<Integer>(subset));
for (int i = end + 1; i < nums.length; ++i) {
if (i > end + 1 && nums[i] == nums[i - 1]) {
continue;
}
subset.add(nums[i]);
queue.offer(new Struct(new ArrayList<Integer>(subset), i));
subset.remove(subset.size() - 1);
}
}
return subsets;
}
}
相似题目:最小子集
lintcode-761
BFS
public class Solution {
public int minElements(int[] arr) {
int minCnt = arr.length;
int sum = getArraySum(arr);
Queue<List<Integer>> queue = new ArrayDeque<List<Integer>>();
queue.offer(new ArrayList<Integer>());
while (!queue.isEmpty()) {
List<Integer> subset = queue.poll();
if (2 * getListSum(subset) > sum) {
minCnt = Math.min(minCnt, subset.size());
}
for (int i = 0; i < arr.length; ++i) {
if (subset.size() > 0 && arr[i] <= subset.get(subset.size() - 1)) {
continue;
}
subset.add(arr[i]);
queue.offer(new ArrayList<Integer>(subset));
subset.remove(subset.size() - 1);
}
}
return minCnt;
}
public int getArraySum(int[] a) {
int sum = 0;
for (int num : a) {
sum += num;
}
return sum;
}
public int getListSum(List<Integer> list) {
int sum = 0;
for (int num : list) {
sum += num;
}
return sum;
}
}
数字组合
lintcode-135
组合型DFS+剪枝
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> combines = new ArrayList<List<Integer>>();
Arrays.sort(candidates);
combineHelper(candidates, target, 0, new ArrayList<Integer>(), combines);
return combines;
}
public void combineHelper(int[] a, int target, int start, List<Integer> combine, List<List<Integer>> combines) {
if (target == 0) {
combines.add(new ArrayList<Integer>(combine));
return;
}
if (target < 0) {
return;
}
for (int i = start; i < a.length; ++i) {
if (i > start && a[i] == a[i - 1]) {
continue;
}
combine.add(a[i]);
combineHelper(a, target - a[i], i, combine, combines);
combine.remove(combine.size() - 1);
}
}
}
相似题目:数字组合II
lintcode-153
组合型DFS+剪枝
public class Solution {
public List<List<Integer>> combinationSum2(int[] num, int target) {
List<List<Integer>> combines = new ArrayList<List<Integer>>();
Arrays.sort(num);
combineHelper(num, target, 0, new ArrayList<Integer>(), combines);
return combines;
}
public void combineHelper(int[] a, int target, int start, List<Integer> combine, List<List<Integer>> combines) {
if (target == 0) {
combines.add(new ArrayList<Integer>(combine));
return;
}
if (target < 0) {
return;
}
for (int i = start; i < a.length; ++i) {
if (i > start && a[i] == a[i - 1]) {
continue;
}
combine.add(a[i]);
combineHelper(a, target - a[i], i + 1, combine, combines);
combine.remove(combine.size() - 1);
}
}
}
全排列
lintcode-15
解法1:排列型DFS
public class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> permutes = new ArrayList<List<Integer>>();
permuteHelper(nums, new boolean[nums.length], new ArrayList<Integer>(), permutes);
return permutes;
}
public void permuteHelper(int[] a, boolean[] isVisited, List<Integer> permute, List<List<Integer>> permutes) {
if (permute.size() == a.length) {
permutes.add(new ArrayList<Integer>(permute));
return;
}
for (int i = 0; i < a.length; ++i) {
if (isVisited[i]) {
continue;
}
permute.add(a[i]);
isVisited[i] = true;
permuteHelper(a, isVisited, permute, permutes);
permute.remove(permute.size() - 1);
isVisited[i] = false;
}
}
}
解法2:非递归
public class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> permutes = new ArrayList<List<Integer>>();
Arrays.sort(nums);
boolean hasNext = true;
while (hasNext) {
permutes.add(arrayToList(nums));
hasNext = nextPermute(nums);
}
return permutes;
}
public boolean nextPermute(int[] a) {
int index = a.length - 1;
while (index > 0 && a[index] <= a[index - 1]) {
index--;
}
if (index <= 0) {
return false;
}
int minMore = a.length - 1;
while (minMore > index && a[minMore] <= a[index - 1]) {
minMore--;
}
swap(a, index - 1, minMore);
reverse(a, index, a.length - 1);
return true;
}
public void swap(int[] a, int p1, int p2) {
int temp = a[p1];
a[p1] = a[p2];
a[p2] = temp;
}
public void reverse(int[] a, int start, int end) {
while (start < end) {
swap(a, start++, end--);
}
}
public List<Integer> arrayToList(int[] a) {
List<Integer> list = new ArrayList<Integer>();
for (int num : a) {
list.add(num);
}
return list;
}
}
相似题目:带重复元素的排列
lintcode-16
解法1:排列型DFS+剪枝
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> permutes = new ArrayList<List<Integer>>();
Arrays.sort(nums);
permuteHelper(nums, new boolean[nums.length], new ArrayList<Integer>(), permutes);
return permutes;
}
public void permuteHelper(int[] a, boolean[] isVisited, List<Integer> permute, List<List<Integer>> permutes) {
if (permute.size() == a.length) {
permutes.add(new ArrayList<Integer>(permute));
return;
}
for (int i = 0; i < a.length; ++i) {
if (isVisited[i] || i > 0 && a[i] == a[i - 1] && !isVisited[i - 1]) {
continue;
}
permute.add(a[i]);
isVisited[i] = true;
permuteHelper(a, isVisited, permute, permutes);
permute.remove(permute.size() - 1);
isVisited[i] = false;
}
}
}
解法2:非递归
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> permutes = new ArrayList<List<Integer>>();
Arrays.sort(nums);
boolean hasNext = true;
while (hasNext) {
permutes.add(arrayToList(nums));
hasNext = nextPermute(nums);
}
return permutes;
}
public boolean nextPermute(int[] a) {
int index = a.length - 1;
while (index > 0 && a[index] <= a[index - 1]) {
index--;
}
if (index <= 0) {
return false;
}
int minMore = a.length - 1;
while (minMore > index && a[minMore] <= a[index - 1]) {
minMore--;
}
swap(a, index - 1, minMore);
reverse(a, index, a.length - 1);
return true;
}
public void swap(int[] a, int p1, int p2) {
int temp = a[p1];
a[p1] = a[p2];
a[p2] = temp;
}
public void reverse(int[] a, int start, int end) {
while (start < end) {
swap(a, start++, end--);
}
}
public List<Integer> arrayToList(int[] a) {
List<Integer> list = new ArrayList<Integer>();
for (int num : a) {
list.add(num);
}
return list;
}
}
相似题目:下一个排列
lintcode-52
算法步骤
- 从右往左遍历数组 nums,直到找到一个位置 i,满足 nums[i]>nums[i-1] 或者 i==0
- i!=0 时,用 j 再次从右到左遍历 nums,寻找第一个 nums[j]>nums[i-1],交换 nums[j] 和 nums[i-1];注意,满足要求的 j 一定存在,且交换后 nums[i] 及右侧数组仍为降序数组
- 将 nums[i] 及右侧的数组翻转,使其升序
public class Solution {
public int[] nextPermutation(int[] nums) {
int rightPeak = nums.length - 1;
while (rightPeak > 0 && nums[rightPeak] <= nums[rightPeak - 1]) {
rightPeak--;
}
if (rightPeak > 0) {
int minMore = nums.length - 1;
while (minMore > rightPeak && nums[minMore] <= nums[rightPeak - 1]) {
minMore--;
}
swap(nums, rightPeak - 1, minMore);
}
reverse(nums, rightPeak, nums.length - 1);
return nums;
}
public void swap(int[] a, int p1, int p2) {
int temp = a[p1];
a[p1] = a[p2];
a[p2] = temp;
}
public void reverse(int[] a, int start, int end) {
while (start < end) {
swap(a, start++, end--);
}
}
}
相似题目:上一个排列
lintcode-51
public class Solution {
public List<Integer> previousPermuation(List<Integer> nums) {
int index = nums.size() - 1;
while (index > 0 && nums.get(index) >= nums.get(index - 1)) {
index--;
}
if (index > 0) {
int maxLess = nums.size() - 1;
while (maxLess > index && nums.get(maxLess) >= nums.get(index - 1)) {
maxLess--;
}
swap(nums, index - 1, maxLess);
}
reverse(nums, index, nums.size() - 1);
return nums;
}
public void swap(List<Integer> list, int p1, int p2) {
int temp = list.get(p1);
list.set(p1, list.get(p2));
list.set(p2, temp);
}
public void reverse(List<Integer> list, int start, int end) {
while (start < end) {
swap(list, start++, end--);
}
}
}
康托展开
cantor-expansion
康托展开:给出排列(按字典排序),求排列序号
X
=
a
n
(
n
−
1
)
!
+
a
n
−
1
(
n
−
2
)
!
+
⋯
+
a
2
⋅
1
!
+
a
1
⋅
0
!
X=a_n(n-1)!+a_{n-1}(n-2)!+\cdots+a_2\cdot 1!+a_1\cdot 0!
X=an(n−1)!+an−1(n−2)!+⋯+a2⋅1!+a1⋅0!
康托函数是双射函数,逆康托展开:给出排列序号,求对应的排列
排列序号
lintcode-197
public class Solution {
public long permutationIndex(int[] a) {
long order = 1, factor = 1;
for (int i = a.length - 1; i >= 0; --i) {
int cntRightLess = countRightLess(a, i);
order += cntRightLess * factor;
factor *= a.length - i;
}
return order;
}
public int countRightLess(int[] a, int index) {
int cnt = 0;
for (int i = index + 1; i < a.length; ++i) {
if (a[i] < a[index]) {
cnt++;
}
}
return cnt;
}
}
排列序号
lintcode-198
public class Solution {
public long permutationIndexII(int[] a) {
long order = 1, factor = 1, repeat = 1;
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = a.length - 1; i >= 0; --i) {
map.put(a[i], map.getOrDefault(a[i], 0) + 1);
repeat *= map.get(a[i]);
int count = countRightLess(a, i);
order += count * factor / repeat;
factor *= a.length - i;
}
return order;
}
public int countRightLess(int[] a, int index) {
int cnt = 0;
for (int i = index + 1; i < a.length; ++i) {
if (a[i] < a[index]) {
cnt++;
}
}
return cnt;
}
}
第k个排列
lintcode-388
public class Solution {
public String getPermutation(int n, int k) {
String permute = new String();
List<Integer> list = constructList(n);
int order = k - 1, factor = calculateFactor(n);
for (int i = 1; i <= n; ++i) {
int cnt = order / factor;
permute += String.valueOf(list.get(cnt));
list.remove(cnt);
order %= factor;
factor = i < n ? factor / (n - i) : 1;
}
return permute;
}
public List<Integer> constructList(int n) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 1; i <= n; ++i) {
list.add(i);
}
return list;
}
public int calculateFactor(int n) {
int product = 1;
for (int i = 2; i < n; ++i) {
product *= i;
}
return product;
}
}
跳马问题
lintcode-611
解法1:BFS
public class Solution {
public int shortestPath(boolean[][] grid, Point source, Point destination) {
int[][] biases = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};
int path = 0;
Queue<Point> queue = new ArrayDeque<Point>();
queue.offer(new Point(source.x, source.y));
grid[source.x][source.y] = true;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; ++i) {
Point curr = queue.poll();
if (curr.x == destination.x && curr.y == destination.y) {
return path;
}
for (int[] bias : biases) {
int nextX = curr.x + bias[0], nextY = curr.y + bias[1];
if (!isValid(grid, nextX, nextY)) {
continue;
}
queue.offer(new Point(nextX, nextY));
grid[nextX][nextY] = true;
}
}
path++;
}
return -1;
}
public boolean isValid(boolean[][] a, int x, int y) {
if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
return false;
}
return !a[x][y];
}
}
解法2:双向BFS
双向BFS适用条件:有起始点,无向图
public class Solution {
public int shortestPath(boolean[][] grid, Point source, Point destination) {
int[][] biases = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};
int path = 0;
Queue<Point> forwQueue = new ArrayDeque<Point>(), backQueue = new ArrayDeque<Point>();
forwQueue.offer(new Point(source.x, source.y));
backQueue.offer(new Point(destination.x, destination.y));
boolean[][] isVisitedForw = new boolean[grid.length][grid[0].length], isVisitedBack = new boolean[grid.length][grid[0].length];
isVisitedForw[source.x][source.y] = true;
isVisitedBack[destination.x][destination.y] = true;
while (!forwQueue.isEmpty() && !backQueue.isEmpty()) {
int forwSize = forwQueue.size(), backSize = backQueue.size();
for (int i = 0; i < forwSize; ++i) {
Point curr = forwQueue.poll();
if (isVisitedBack[curr.x][curr.y]) {
return path;
}
for (int[] bias : biases) {
int nextX = curr.x + bias[0], nextY = curr.y + bias[1];
if (!isValid(grid, nextX, nextY) || isVisitedForw[nextX][nextY]) {
continue;
}
forwQueue.offer(new Point(nextX, nextY));
isVisitedForw[nextX][nextY] = true;
}
}
path++;
for (int i = 0; i < backSize; ++i) {
Point curr = backQueue.poll();
if (isVisitedForw[curr.x][curr.y]) {
return path;
}
for (int[] bias : biases) {
int nextX = curr.x + bias[0], nextY = curr.y + bias[1];
if (!isValid(grid, nextX, nextY) || isVisitedBack[nextX][nextY]) {
continue;
}
backQueue.offer(new Point(nextX, nextY));
isVisitedBack[nextX][nextY] = true;
}
}
path++;
}
return -1;
}
public boolean isValid(boolean[][] a, int x, int y) {
if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
return false;
}
return !a[x][y];
}
}
相似问题:跳马问题II
lintcode-630
解法1:BFS
public class Solution {
public int shortestPath2(boolean[][] grid) {
int[][] biases = {{1, 2}, {-1, 2}, {2, 1}, {-2, 1}};
int path = 0;
Queue<int[]> queue = new ArrayDeque<int[]>();
queue.offer(new int[]{0, 0});
grid[0][0] = true;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; ++i) {
int[] curr = queue.poll();
if (curr[0] == grid.length - 1 && curr[1] == grid[0].length - 1) {
return path;
}
for (int[] bias : biases) {
int nextX = curr[0] + bias[0], nextY = curr[1] + bias[1];
if (!isValid(grid, nextX, nextY)) {
continue;
}
queue.offer(new int[]{nextX, nextY});
grid[nextX][nextY] = true;
}
}
path++;
}
return -1;
}
public boolean isValid(boolean[][] a, int x, int y) {
if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
return false;
}
return !a[x][y];
}
}
解法2:双向BFS
解法3:坐标型DP
public class Solution {
public int shortestPath2(boolean[][] grid) {
int[][] biases = {{1, 2}, {-1, 2}, {2, 1}, {-2, 1}};
int[][] state = new int[grid.length][grid[0].length];
for (int[] a : state) {
Arrays.fill(a, -1);
}
state[0][0] = 0;
for (int y = 0; y < grid[0].length; ++y) {
for (int x = 0; x < grid.length; ++x) {
if (grid[x][y]) {
continue;
}
int minPath = Integer.MAX_VALUE;
for (int[] bias : biases) {
if (!isValid(grid, x - bias[0], y - bias[1])) {
continue;
}
if (state[x - bias[0]][y - bias[1]] > -1) {
minPath = Math.min(minPath, state[x - bias[0]][y - bias[1]]);
}
}
if (minPath < Integer.MAX_VALUE) {
state[x][y] = minPath + 1;
}
}
}
return state[grid.length - 1][grid[0].length - 1];
}
public boolean isValid(boolean[][] a, int x, int y) {
if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
return false;
}
return !a[x][y];
}
}
迷宫
lintcode-787
解法1:BFS
public class Solution {
public boolean hasPath(int[][] maze, int[] start, int[] destination) {
int[][] biases = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
Queue<int[]> queue = new ArrayDeque<int[]>();
queue.offer(start);
boolean[][] isVisited = new boolean[maze.length][maze[0].length];
while (!queue.isEmpty()) {
int[] curr = queue.poll();
isVisited[curr[0]][curr[1]] = true;
if (curr[0] == destination[0] && curr[1] == destination[1]) {
return true;
}
for (int[] bias : biases) {
int[] next = getNext(maze, curr[0], curr[1], bias);
if (!isValid(maze, next[0], next[1]) || isVisited[next[0]][next[1]]) {
continue;
}
queue.offer(next);
}
}
return false;
}
public int[] getNext(int[][] a, int x, int y, int[] bias) {
while (isValid(a, x, y)) {
x += bias[0];
y += bias[1];
}
return new int[]{x - bias[0], y - bias[1]};
}
public boolean isValid(int[][] a, int x, int y) {
if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
return false;
}
return a[x][y] == 0;
}
}
解法2:双向BFS
相似问题:迷宫II
lintcode-788
解法1:BFS
public class Solution {
public int shortestDistance(int[][] maze, int[] start, int[] destination) {
int[][] biases = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
Queue<int[]> queue = new ArrayDeque<int[]>();
queue.offer(start);
int[][] path = new int[maze.length][maze[0].length];
for (int[] a : path) {
Arrays.fill(a, -1);
}
path[start[0]][start[1]] = 0;
while (!queue.isEmpty()) {
int[] curr = queue.poll();
for (int[] bias : biases) {
int[] next = getNextAndStep(maze, curr[0], curr[1], bias);
if (curr[0] == next[0] && curr[1] == next[1]) {
continue;
}
int nextPath = path[curr[0]][curr[1]] + next[2];
if (path[next[0]][next[1]] == -1 || nextPath < path[next[0]][next[1]]) {
path[next[0]][next[1]] = nextPath;
queue.offer(new int[]{next[0], next[1]});
}
}
}
return path[destination[0]][destination[1]];
}
public int[] getNextAndStep(int[][] a, int x, int y, int[] bias) {
int cntStep = -1;
while (isValid(a, x, y)) {
x += bias[0];
y += bias[1];
cntStep++;
}
return new int[]{x - bias[0], y - bias[1], cntStep};
}
public boolean isValid(int[][] a, int x, int y) {
if (x < 0 || x >= a.length || y < 0 || y >= a[0].length) {
return false;
}
return a[x][y] == 0;
}
}
解法2:双向BFS
单词接龙
lintcode-120
解决BFS问题先构图(无向or有向):Map<Type>: Type -> Set<Type>
解法1:BFS
public class Solution {
public int ladderLength(String start, String end, Set<String> dict) {
int path = 1;
dict.add(start);
dict.add(end);
Map<String, Set<String>> graph = constructGraph(dict);
Queue<String> queue = new ArrayDeque<String>();
queue.offer(start);
dict.remove(start);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; ++i) {
String curr = queue.poll();
if (curr.equals(end)) {
return path;
}
for (String next : graph.get(curr)) {
if (!dict.contains(next)) {
continue;
}
queue.offer(next);
dict.remove(next);
}
}
path++;
}
return -1;
}
public Map<String, Set<String>> constructGraph(Set<String> dict) {
Map<String, Set<String>> graph = new HashMap<String, Set<String>>();
for (String word : dict) {
Set<String> nexts = getNextWords(word, dict);
graph.put(word, nexts);
}
return graph;
}
public Set<String> getNextWords(String word, Set<String> dict) {
Set<String> nexts = new HashSet<String>();
char[] alphabet = ("abcdefghijklmnopqrstuvwxyz").toCharArray();
for (int i = 0; i < word.length(); ++i) {
String prefix = word.substring(0, i), suffix = word.substring(i + 1);
for (int j = 0; j < 26; ++j) {
if (word.charAt(i) == alphabet[j]) {
continue;
}
String next = prefix + alphabet[j] + suffix;
if (dict.contains(next)) {
nexts.add(next);
}
}
}
return nexts;
}
}
解法2:双向BFS
public class Solution {
public int ladderLength(String start, String end, Set<String> dict) {
int path = 1;
dict.add(start);
dict.add(end);
Map<String, Set<String>> graph = constructGraph(dict);
Queue<String> forwQueue = new ArrayDeque<String>(), backQueue = new ArrayDeque<String>();
forwQueue.offer(start);
backQueue.offer(end);
Set<String> forwSet = new HashSet<String>(), backSet = new HashSet<String>();
forwSet.add(start);
backSet.add(end);
while (!forwQueue.isEmpty() && !backQueue.isEmpty()) {
int forwSize = forwQueue.size(), backSize = backQueue.size();
for (int i = 0; i < forwSize; ++i) {
String curr = forwQueue.poll();
if (backSet.contains(curr)) {
return path;
}
for (String next : graph.get(curr)) {
if (forwSet.contains(next)) {
continue;
}
forwQueue.offer(next);
forwSet.add(next);
}
}
path++;
for (int i = 0; i < backSize; ++i) {
String curr = backQueue.poll();
if (forwSet.contains(curr)) {
return path;
}
for (String next : graph.get(curr)) {
if (backSet.contains(next)) {
continue;
}
backQueue.offer(next);
backSet.add(next);
}
}
path++;
}
return -1;
}
public Map<String, Set<String>> constructGraph(Set<String> dict) {
Map<String, Set<String>> graph = new HashMap<String, Set<String>>();
for (String word : dict) {
Set<String> nexts = getNextWords(word, dict);
graph.put(word, nexts);
}
return graph;
}
public Set<String> getNextWords(String word, Set<String> dict) {
Set<String> nexts = new HashSet<String>();
char[] alphabet = ("abcdefghijklmnopqrstuvwxyz").toCharArray();
for (int i = 0; i < word.length(); ++i) {
String prefix = word.substring(0, i), suffix = word.substring(i + 1);
for (int j = 0; j < 26; ++j) {
if (word.charAt(i) == alphabet[j]) {
continue;
}
String next = prefix + alphabet[j] + suffix;
if (dict.contains(next)) {
nexts.add(next);
}
}
}
return nexts;
}
}
相似问题:单词接龙II
linrcode-121
BFS+DFS
数独
lintcode-802
解法1:DFS
public class Solution {
public void solveSudoku(int[][] board) {
boolean[][] row = new boolean[9][10], col = new boolean[9][10], box = new boolean[9][10];
getIntialized(board, row, col, box);
sudokuHelper(board, 0, row, col, box);
}
public boolean sudokuHelper(int[][] a, int index, boolean[][] row, boolean[][] col, boolean[][] box) {
if (index == 81) {
return true;
}
int x = index / 9, y = index % 9;
if (a[x][y] > 0) {
return sudokuHelper(a, index + 1, row, col, box);
}
for (int value = 1; value <= 9; ++value) {
if (!isValid(x, y, value, row, col, box)) {
continue;
}
a[x][y] = value;
row[x][value] = true;
col[y][value] = true;
box[x / 3 * 3 + y / 3][value] = true;
if (sudokuHelper(a, index + 1, row, col, box)) {
return true;
}
a[x][y] = 0;
row[x][value] = false;
col[y][value] = false;
box[x / 3 * 3 + y / 3][value] = false;
}
return false;
}
public void getIntialized(int[][] a, boolean[][] row, boolean[][] col, boolean[][] box) {
for (int i = 0; i < 81; ++i) {
int x = i / 9, y = i % 9, value = a[x][y];
if (value == 0) {
continue;
}
row[x][value] = true;
col[y][value] = true;
box[x / 3 * 3 + y / 3][value] = true;
}
}
public boolean isValid(int x, int y, int value, boolean[][] row, boolean[][] col, boolean[][] box) {
if (row[x][value] || col[y][value]) {
return false;
} // row, col
if (box[x / 3 * 3 + y / 3][value]) {
return false;
} // 9x9 box
return true;
}
}
public class Solution {
public void solveSudoku(int[][] board) {
sudokuHelper(board, 0);
}
public boolean sudokuHelper(int[][] a, int index) {
if (index == 81) {
return true;
}
int x = index / 9, y = index % 9;
if (a[x][y] > 0) {
return sudokuHelper(a, index + 1);
}
for (int value = 1; value <= 9; ++value) {
if (!isValid(a, x, y, value)) {
continue;
}
a[x][y] = value;
if (sudokuHelper(a, index + 1)) {
return true;
}
a[x][y] = 0;
}
return false;
}
public boolean isValid(int[][] a, int x, int y, int value) {
for (int i = 0; i < 9; ++i) {
if (a[x][i] == value || a[i][y] == value) {
return false;
} // row, col
if (a[x / 3 * 3 + i / 3][y / 3 * 3 + i % 3] == value) {
return false;
} // 9x9 box
}
return true;
}
}
解法2:DFS+搜索顺序优化
旅行商问题
lintcode-816
解法1:DFS
public class Solution {
class Result {
private int minCost;
public Result() {
this.minCost = Integer.MAX_VALUE;
}
}
public int minCost(int n, int[][] roads) {
Result minCost = new Result();
int[][] adjacentMatrix = getAdjacentMatrix(roads, n);
Set<Integer> visitedNodeSet = new HashSet<Integer>();
visitedNodeSet.add(1);
minCostHelper(n, 1, adjacentMatrix, 0, visitedNodeSet, minCost);
return minCost.minCost;
}
public void minCostHelper(int n, int curNode, int[][] adjacentMatrix, int totalCost, Set<Integer> visitedNodeSet, Result minCost) {
if (visitedNodeSet.size() == n) {
minCost.minCost = Math.min(minCost.minCost, totalCost);
return;
}
for (int nexNode = 1; nexNode <= n; ++nexNode) {
if (visitedNodeSet.contains(nexNode)) {
continue;
}
visitedNodeSet.add(nexNode);
minCostHelper(n, nexNode, adjacentMatrix, totalCost + adjacentMatrix[curNode][nexNode], visitedNodeSet, minCost);
visitedNodeSet.remove(nexNode);
}
}
public int[][] getAdjacentMatrix(int[][] edges, int numNode) {
int[][] matrix = new int[numNode + 1][numNode + 1];
for (int i = 0; i <= numNode; ++i) {
for (int j = 0; j <= numNode; ++j) {
matrix[i][j] = Integer.MAX_VALUE >> 4;
}
}
for (int i = 0; i < edges.length; ++i) {
int a = edges[i][0];
int b = edges[i][1];
int c = edges[i][2];
matrix[a][b] = Math.min(matrix[a][b], c);
matrix[b][a] = Math.min(matrix[b][a], c);
} // initialization
return matrix;
}
}
解法2:DFS+最优化剪枝
public class Solution {
class Result {
private int minCost;
public Result() {
this.minCost = Integer.MAX_VALUE;
}
}
public int minCost(int n, int[][] roads) {
Result minCost = new Result();
List<Integer> path = new ArrayList<Integer>();
path.add(1);
Set<Integer> visitedNodeSet = new HashSet<Integer>();
visitedNodeSet.add(1);
int[][] adjacentMatrix = getAdjacentMatrix(roads, n);
minCostHelper(n, 1, path, visitedNodeSet, adjacentMatrix, 0, minCost);
return minCost.minCost;
}
public void minCostHelper(int n, int curNode, List<Integer> path, Set<Integer> visitedNodeSet, int[][] adjacentMatrix, int totalCost, Result minCost) {
if (visitedNodeSet.size() == n) {
minCost.minCost = Math.min(minCost.minCost, totalCost);
return;
}
for (int nexNode = 1; nexNode <= n; ++nexNode) {
if (visitedNodeSet.contains(nexNode) || hasBetterCase(nexNode, path, adjacentMatrix)) {
continue;
}
path.add(nexNode);
visitedNodeSet.add(nexNode);
minCostHelper(n, nexNode, path, visitedNodeSet, adjacentMatrix, totalCost + adjacentMatrix[curNode][nexNode], minCost);
visitedNodeSet.remove(nexNode);
path.remove(path.size() - 1);
}
}
public boolean hasBetterCase(int node, List<Integer> path, int[][] adjacentMatrix) {
for (int i = 1; i < path.size(); ++i) {
if (adjacentMatrix[path.get(i - 1)][path.get(i)] + adjacentMatrix[path.get(path.size() - 1)][node] > adjacentMatrix[path.get(i - 1)][path.get(path.size() - 1)] + adjacentMatrix[path.get(i)][node]) {
return true;
}
}
return false;
}
public int[][] getAdjacentMatrix(int[][] edges, int numNode) {
int[][] matrix = new int[numNode + 1][numNode + 1];
for (int i = 0; i <= numNode; ++i) {
for (int j = 0; j <= numNode; ++j) {
matrix[i][j] = Integer.MAX_VALUE >> 4;
}
}
for (int i = 0; i < edges.length; ++i) {
int a = edges[i][0];
int b = edges[i][1];
int c = edges[i][2];
matrix[a][b] = Math.min(matrix[a][b], c);
matrix[b][a] = Math.min(matrix[b][a], c);
} // initialization
return matrix;
}
}
解法3:状态压缩DP
public class Solution {
public int minCost(int n, int[][] roads) {
int minCost = Integer.MAX_VALUE;
int sizeState = 1 << n;
int[][] stateNode = getStateNode(sizeState, n);
int[][] adjacentMatrix = getAdjacentMatrix(roads, n);
for (int curState = 0; curState < sizeState; ++curState) {
for (int curNode = 2; curNode <= n; ++curNode) {
if ((curState & 1 << (curNode - 1)) == 0) {
continue;
}
int preState = curState ^ 1 << (curNode - 1);
for (int preNode = 1; preNode <= n; ++preNode) {
if ((preState & 1 << (preNode - 1)) == 0) {
continue;
}
stateNode[curState][curNode] = Math.min(stateNode[curState][curNode], stateNode[preState][preNode] + adjacentMatrix[preNode][curNode]);
}
}
}
for (int node = 1; node <= n; ++node) {
minCost = Math.min(minCost, stateNode[sizeState - 1][node]);
}
return minCost;
}
public int[][] getStateNode(int sizeState, int numNode) {
int[][] matrix = new int[sizeState][numNode + 1];
for (int i = 0; i < sizeState; ++i) {
for (int j = 0; j <= numNode; ++j) {
matrix[i][j] = Integer.MAX_VALUE >> 4;
}
}
matrix[1][1] = 0; // initialization
return matrix;
}
public int[][] getAdjacentMatrix(int[][] edges, int numNode) {
int[][] matrix = new int[numNode + 1][numNode + 1];
for (int i = 0; i <= numNode; ++i) {
for (int j = 0; j <= numNode; ++j) {
matrix[i][j] = Integer.MAX_VALUE >> 4;
}
}
for (int i = 0; i < edges.length; ++i) {
int a = edges[i][0];
int b = edges[i][1];
int c = edges[i][2];
matrix[a][b] = Math.min(matrix[a][b], c);
matrix[b][a] = Math.min(matrix[b][a], c);
} // initialization
return matrix;
}
}
解法4:随机化算法
public class Solution {
public int RANDOM_TIME = 1000;
public Random rand = new Random(1000);
public int minCost(int n, int[][] roads) {
int minCost = Integer.MAX_VALUE;
int[][] adjacentMatrix = getAdjacentMatrix(roads, n);
for (int time = 0; time < RANDOM_TIME; ++time) {
List<Integer> path = getRandomPath(n);
int cost = adjustToBetterCase(n, path, adjacentMatrix);
minCost = Math.min(minCost, cost);
}
return minCost;
}
// all random permutation is with the same probability
public List<Integer> getRandomPath(int numNode) {
List<Integer> path = new ArrayList<Integer>();
for (int i = 1; i <= numNode; ++i) {
path.add(i);
}
for (int i = 2; i < numNode; ++i) {
int j = rand.nextInt(1000) % i + 1; // [0, i) -> [1, i]
swap(path, i, j);
}
return path;
}
public int[][] getAdjacentMatrix(int[][] edges, int numNode) {
int[][] matrix = new int[numNode + 1][numNode + 1];
for (int i = 0; i <= numNode; ++i) {
for (int j = 0; j <= numNode; ++j) {
matrix[i][j] = Integer.MAX_VALUE >> 4;
}
}
for (int i = 0; i < edges.length; ++i) {
int a = edges[i][0];
int b = edges[i][1];
int c = edges[i][2];
matrix[a][b] = Math.min(matrix[a][b], c);
matrix[b][a] = Math.min(matrix[b][a], c);
} // initialization
return matrix;
}
public int adjustToBetterCase(int numNode, List<Integer> path, int[][] adjacentMatrix) {
int cost = 0;
boolean isAdjusted = true;
while (isAdjusted) {
isAdjusted = false;
for (int i = 1; i < numNode; ++i) {
for (int j = i + 1; j < numNode; ++j) {
// swap strategy
if (canSwap(i, j, path, adjacentMatrix)) {
swap(path, i, j);
isAdjusted = true;
}
// // reverse strategy
// if (canReverse(i, j, path, adjacentMatrix)) {
// reverse(path, i, j);
// isAdjusted = true;
// }
}
}
}
for (int node = 1; node < numNode; ++node) {
cost += adjacentMatrix[path.get(node - 1)][path.get(node)];
}
return cost;
}
public boolean canSwap(int i, int j, List<Integer> path, int[][] adjacentMatrix) {
int before = adjacentMatrix[path.get(i - 1)][path.get(i)] + adjacentMatrix[path.get(i)][path.get(i + 1)] + adjacentMatrix[path.get(j - 1)][path.get(j)];
int after = adjacentMatrix[path.get(i - 1)][path.get(j)] + adjacentMatrix[path.get(j)][path.get(i + 1)] + adjacentMatrix[path.get(j - 1)][path.get(i)];
if (j + 1 < path.size()) {
before += adjacentMatrix[path.get(j)][path.get(j + 1)];
after += adjacentMatrix[path.get(i)][path.get(j + 1)];
}
return before > after;
}
// reverse strategy can be used only when: adjacentMatrix[i][j] == adjacentMatrix[j][i]
public boolean canReverse(int i, int j, List<Integer> path, int[][] adjacentMatrix) {
int before = adjacentMatrix[path.get(i - 1)][path.get(i)];
int after = adjacentMatrix[path.get(i - 1)][path.get(j)];
if (j + 1 < path.size()) {
before += adjacentMatrix[path.get(j)][path.get(j + 1)];
after += adjacentMatrix[path.get(i)][path.get(j + 1)];
}
return before > after;
}
public void swap(List<Integer> a, int p1, int p2) {
int temp = a.get(p1);
a.set(p1, a.get(p2));
a.set(p2, temp);
}
public void reverse(List<Integer> a, int start, int end) {
while (start < end) {
swap(a, start++, end--);
}
}
}