回溯算法及相关练习题
回溯
决策树的遍历过程
1. 路径:已经做出的选择
2. 选择列表:当前可以做的选择
3. 结束条件:到达决策树底层,无法再做选择的条件
result = []
def backtrack(路径, 选择列表):
if (满足结束条件) :
result.add(路径)
return
for 选择 in 选择列表:
do 选择
backtrack( 路径,选择列表)
撤销选择
leetcode 46:全排列
List<List<Integer>> res = new LinkedList<>();
/* 主函数,输入一组不重复的数字,返回它们的全排列 */
List<List<Integer>> permute(int[] nums) {
// 记录「路径」
LinkedList<Integer> track = new LinkedList<>();
backtrack(nums, track);
return res;
}
// 路径:记录在 track 中
// 选择列表:nums 中不存在于 track 的那些元素
// 结束条件:nums 中的元素全都在 track 中出现
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();
}
}
leetcode 51: N皇后
package com.yuanhaosheng.backTrack;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class _51_NQueen {
List<List<String>> res = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
char[][] chessBoard = new char[n][n];
for (char[] chars : chessBoard) {
Arrays.fill(chars, '.');
}
backTrack(n, 0, chessBoard);
return res;
}
private void backTrack(int n, int row, char[][] chessBoard) {
if (row == n) {
res.add(Array2List(chessBoard));
return;
}
// n * n
for (int i = 0; i < n; i++) {
if (isValid(row, i, chessBoard)) {
chessBoard[row][i] = 'Q';
backTrack(n, row + 1, chessBoard);
chessBoard[row][i] = '.';
}
}
}
private List<String> Array2List(char[][] chessBoard) {
List<String> list = new ArrayList<>();
for (int i = 0; i < chessBoard.length; i++) {
list.add(String.copyValueOf(chessBoard[i]));
}
return list;
}
private boolean isValid(int row, int col, char[][] chessBoard) {
for (int i = row, j = col; i >= 0 && j >= 0; j--, i--) {
if (chessBoard[i][j] == 'Q') {
return false;
}
}
for (int i = row, j = col; i >= 0; i--) {
if (chessBoard[i][j] == 'Q') {
return false;
}
}
for (int i = row, j = col; i >= 0 && j < chessBoard.length; i--, j++) {
if (chessBoard[i][j] == 'Q') {
return false;
}
}
return true;
}
}
// foreign pirateutopia // 人名
private boolean validate(char[][] board, int x, int y) {
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < y; j++) {
if(board[i][j] == 'Q' && (x + j == y + i || x + y == i + j || x == i))
return false;
}
}
return true;
}
leetcode 78: 子集
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
// 记录「路径」
LinkedList<Integer> track = new LinkedList<>();
backtrack(nums, 0, track);
return res;
}
private void backtrack(int[] nums, int start, LinkedList<Integer> track) {
res.add(new LinkedList<>(track));
for (int i = start; i < nums.length; i++) {
track.add(nums[i]);
backtrack(nums, i + 1, track);
track.removeLast();
}
}
}
public class Subset {
private void backtrack(int[] nums, int level, LinkedList<Integer> track) {
if (level == nums.length) {
res.add(new LinkedList<>(track));
}
backtrack(nums, level + 1, track);
track.add(nums[level]);
backtrack(nums, level + 1, track);
track.removeLast();
}
}
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, 0);
return list;
}
private void backtrack(List<List<Integer>> list , List<Integer> tempList, int [] nums, int start){
list.add(new ArrayList<>(tempList));
for(int i = start; i < nums.length; i++){
tempList.add(nums[i]);
backtrack(list, tempList, nums, i + 1);
tempList.remove(tempList.size() - 1);
}
}
leetcode 494 目标和
class Solution {
private int result = 0;
public int findTargetSumWays(int[] nums, int target) {
backTrack(nums, 0, target, 0);
return result;
}
private void backTrack(int[] nums,int index, int target, int sum) {
if ( index == nums.length) {
if (sum == target)
result++;
return;
}
// for (int i = index; i < nums.length; i++) {
backTrack(nums, index + 1, target,sum + nums[index]);
backTrack(nums, index + 1, target,sum - nums[index]);
// }
}
}
leetcode 39. 组合总和
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<>();
backTrack(candidates, target, 0, 0, new ArrayList<>(), result);
return result;
}
private void backTrack(int[] candidates, int target, int sum, int start, ArrayList<Integer> list, List<List<Integer>> result) {
if (sum == target) {
result.add(new ArrayList<Integer>(list));
return;
}
if (sum > target) {return;}
for (int i = start; i < candidates.length; i++) {
list.add(candidates[i]);
backTrack(candidates, target, sum + candidates[i], i, list, result);
list.remove(list.size() - 1);
}
}
}
leetcode 40. 组合总和 II
class Solution {
private List<List<Integer>> result;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
result = new ArrayList<>();
Arrays.sort(candidates);
backTrack(candidates, target, 0, new ArrayList<>());
return result;
}
private void backTrack(int[] candidates, int target, int start, ArrayList<Integer> list) {
if (target <= 0) {
if (target == 0) {
if (!result.contains(new ArrayList<>(list))) {
result.add(new ArrayList<>(list));
}
}
return;
}
for (int i = start; i < candidates.length; i++) {
list.add(candidates[i]);
backTrack(candidates, target - candidates[i], i + 1, list);
list.remove(list.size() - 1);
}
}
}
39 和 40 https://blog.csdn.net/zy854816286/article/details/105716220
这个博客,写的挺好的。
leetcode 698. 划分为k个相等的子集
用数组视角遍历:每个数字选择哪个桶。
class Solution {
public boolean canPartitionKSubsets(int[] nums, int k) {
if (k > nums.length) return false;
int sum = 0;
for (int num : nums) sum += num;
if (sum % k != 0) return false;
int[] bucket = new int[k];
int target = sum / k;
return backTrack(nums, k, 0, target, bucket);
}
private boolean backTrack(int[] nums, int k, int level, int target, int[] bucket) {
if (level == nums.length) {
for (int i = 0; i < bucket.length - 1; i++) {
if (bucket[i] != bucket[i + 1])
return false;
}
return true;
}
// 选择哪个桶装 自己
for (int i = 0; i < k; i++) {
if (bucket[i] + nums[level] > target) {
continue;
}
bucket[i] += nums[level];
if (backTrack(nums, k, level + 1, target, bucket)) {
return true;
}
bucket[i] -= nums[level];
}
return false;
}
}
用桶的视角:
分治
Java
private static int divide_conquer(Problem problem, ) {
if (problem == NULL) {
int res = process_last_result();
return res;
}
subProblems = split_problem(problem)
res0 = divide_conquer(subProblems[0])
res1 = divide_conquer(subProblems[1])
result = process_result(res0, res1);
return result;
}
leetcode 50. Pow(x, n)
class Solution {
public double myPow(double x, long n) {
if(n == 0)
return 1;
if(n<0){
n = -n;
x = 1/x;
}
return (n%2 == 0) ? myPow(x*x, n/2) : x*myPow(x*x, n/2);
}
}

浙公网安备 33010602011771号