回溯法(深度优先)相关题目
组合
思想:题目要求返回组合数而不是排序数,即不要求k个数有顺序,返回[1,2]和[2,1]是一样的。本题直接按照深度有限的经典思想去做,在递归过程中list集合中元素的个数等于k即可将list中的元素整体添加到返回结果中,并直接返回防止多余的递归。
class Solution {
public List<List<Integer>> res=new ArrayList<>();
public List<List<Integer>> combine(int n, int k) {
List<Integer> list=new ArrayList<>();
dfs(n,k,1,list);
return res;
}
public void dfs(int n,int k,int start,List<Integer> list){
if (list.size()==k){
res.add(new ArrayList<>(list));
return;
}
for (int i=start;i<=n;i++){
list.add(i);
dfs(n,k,i+1,list);
list.remove(list.size()-1);
}
}
}
组合总和
思想:深度优先思想,当递归到某个值等于target时将当前集合中的元素添加到结果中,并且返回,当前集合中元素的总和大于target时也是直接返回,否则白浪费递归时间。
class Solution {
List<List<Integer>> res=new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<Integer> list=new ArrayList<>();
dfs(candidates,target,list,0,0);
return res;
}
public void dfs(int[] candidates,int target,List<Integer> list,int sum,int index){
if (sum==target){
res.add(new ArrayList<>(list));
return;
}
if (sum>target){
return;
}
for (int i=index;i<candidates.length;i++){
list.add(candidates[i]);
dfs(candidates, target, list,sum+candidates[i],i);
list.remove(list.size() - 1);
}
}
}
子集
class Solution {
private List<List<Integer>> res=new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
List<Integer> temp=new ArrayList<>();
res.add(new ArrayList<>());
dfs(nums,0,temp);
return res;
}
public void dfs(int[] nums,int index,List<Integer> temp){
for(int i=index;i<nums.length;i++){
temp.add(nums[i]);
res.add(new ArrayList<>(temp));
dfs(nums,i+1,temp);
temp.remove(temp.size()-1);
}
}
}
括号生成
class Solution {
private List<String> result=new ArrayList<>();
public List<String> generateParenthesis(int n) {
char[] kuohao=new char[n*2];
traceback(kuohao,0);
return result;
}
public void traceback(char kuohao[],int index){
if (index==kuohao.length){
if (match(kuohao)){
result.add(new String(kuohao));
}
}else {
kuohao[index]='(';
traceback(kuohao,index+1);
kuohao[index]=')';
traceback(kuohao,index+1);
}
}
public boolean match(char[] kuohao){
int x=0;
for (int i=0;i<kuohao.length;i++){
if (kuohao[i]=='('){
x++;
}else {
x--;
}
if (x<0){
return false;
}
}
return x==0;
}
}
n皇后
class Solution {
private List<List<String>> result=new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
char[][] chars=new char[n][n];
for (int i=0;i<n;i++){
for (int j=0;j<n;j++){
chars[i][j]='.';
}
}
boolean col[]=new boolean[n];
List<String> slist=new ArrayList<>();
dfs(0,col,chars,slist);
return result;
}
public void dfs(int row,boolean[] col,char[][] chars,List<String> slist){
if (row==chars.length){
result.add(new ArrayList<String>(slist));
return;
}
for (int i=0;i<chars.length;i++){
if (!col[i]&&valid(row,i,chars)){
chars[row][i]='Q';
col[i]=true;
slist.add(new String(chars[row]));
dfs(row+1,col,chars,slist);
slist.remove(slist.size()-1);
col[i]=false;
chars[row][i]='.';
}
}
}
public boolean valid(int row,int col,char[][] chars){
for (int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){
if (chars[i][j]=='Q'){
return false;
}
}
for (int i=row-1,j=col+1;i>=0&&j<chars.length;i--,j++){
if (chars[i][j]=='Q'){
return false;
}
}
return true;
}
}
计算各个位数不同的数字个数
class Solution {
public int countNumbersWithUniqueDigits(int n) {
if (n == 0) return 1;
return dfs(n, 0, new boolean[10]);
}
private int dfs(int n, int idx, boolean[] used) {
int count = 0;
if (idx != n) {
for (int i = 0; i < 10; i++) {
// 剪枝:多位数时,第一个数字不能为0
if (i == 0 && n > 1 && idx == 1) {
continue;
}
// 剪枝:不能使用用过的数字
if (used[i]) {
continue;
}
used[i] = true;
count += dfs(n, idx + 1, used) + 1;
used[i] = false;
}
}
return count;
}
}
子集二
class Solution {
private List<List<Integer>> result=new ArrayList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
deep(nums,0,new ArrayList<>());
return result;
}
public void deep(int[] nums,int index,List<Integer> list){
result.add(new ArrayList<>(list));
while (index<nums.length){
list.add(nums[index]);
deep(nums,index+1,list);
list.remove(list.size()-1);
while (index+1<nums.length&&nums[index+1]==nums[index]){
index++;
}
index++;
}
}
}
单词搜索
class Solution {
public boolean exist(char[][] board, String word) {
boolean[][] flag=new boolean[board.length][board[0].length];
for (int i=0;i<board.length;i++){
for (int j=0;j<board[0].length;j++){
if (word.charAt(0)==board[i][j]){
flag[i][j]=true;
if (find(board,i,j,1,word,flag)){
return true;
}
flag[i][j]=false;
}
}
}
return false;
}
public boolean find(char[][] board,int i,int j,int index,String word,boolean[][] flag){
if (index==word.length()){
return true;
}
if (i<board.length-1 && !flag[i+1][j] && board[i+1][j]==word.charAt(index)){
flag[i+1][j]=true;
boolean result = find(board, i + 1, j, index + 1, word,flag);
if (result){
return result;
}else {
flag[i+1][j]=false;
}
}
if (j<board[0].length-1 && !flag[i][j+1] && board[i][j+1]==word.charAt(index)){
flag[i][j+1]=true;
boolean result = find(board, i , j+1, index + 1, word,flag);
if (result){
return result;
}else {
flag[i][j+1]=false;
}
}
if(i>0 && !flag[i-1][j] && board[i-1][j]==word.charAt(index)){
flag[i-1][j]=true;
boolean result = find(board, i - 1, j, index + 1, word,flag);
if (result){
return result;
}else {
flag[i-1][j]=false;
}
}
if (j>0 && !flag[i][j-1] && board[i][j-1]==word.charAt(index)){
flag[i][j-1]=true;
boolean result = find(board, i , j-1, index + 1, word,flag);
if (result){
return result;
}else {
flag[i][j-1]=false;
}
}
return false;
}
}
边界着色
主要思想:用深度优先的思想,首先判断当前点是否为边界点,判断的依据如judge方法,用rowIndex和colIndex记录边界点的横坐标和纵坐标,判断完成后用visited数组标记该点已被访问(否则下次其他点递归到该点时还会进行判断),然后去遍历数组中的当前点的上、下、左、右的点。遍历能继续进行的条件就是当前元素的值等于初始元素的值,并且当前元素没有被遍历过。
class Solution {
public static boolean[][] visited;
public static int rowColor;
public static List<Integer> rowIndex;
public static List<Integer> colIndex;
public int[][] colorBorder(int[][] grid, int row, int col, int color) {
rowIndex=new ArrayList<>();
colIndex= new ArrayList<>();
visited = new boolean[grid.length][grid[0].length];
rowColor =grid[row][col];
dfs(grid,row,col);
for (int i=0;i<rowIndex.size();i++){
grid[rowIndex.get(i)][colIndex.get(i)] = color;
}
return grid;
}
public void dfs(int[][] grid, int row,int col){
if(grid[row][col]==rowColor && !visited[row][col]){
if (judge(grid,row,col)){ //如果是边界
rowIndex.add(row);
colIndex.add(col);
}
visited[row][col]=true;
if (row>0) dfs(grid,row-1,col);
if (row<grid.length-1) dfs(grid,row+1,col);
if (col>0) dfs(grid,row,col-1);
if (col<grid[0].length-1) dfs(grid,row,col+1);
}
}
public boolean judge(int[][] grid, int row,int col){
if (row==0 || col==0 || row==grid.length-1 || col==grid[0].length-1) return true;
return grid[row - 1][col] != rowColor || grid[row + 1][col] != rowColor || grid[row][col - 1] != rowColor || grid[row][col + 1] != rowColor;
}
}