回溯算法及相关练习题

回溯

决策树的遍历过程

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);
    }
}

leetcode

posted @ 2021-10-11 18:34  大D同学  阅读(185)  评论(0)    收藏  举报