回溯相关题目

一:排列问题

题目描述:

 

 

 

 

二:组合问题

题目描述:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。

说明:

  • 所有数字(包括 target)都是正整数。
  • 解集不能包含重复的组合。 

示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]
示例 2:输入: candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]
import java.util.ArrayList;
import java.util.List;

class Solution {
    List<List<Integer>> res=new ArrayList<List<Integer>>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
       // List<List<Integer>> res=new ArrayList<List<Integer>>();
        if(candidates==null)
            return res;
        ArrayList<Integer> list=new ArrayList<Integer>();
        f(target,0,candidates,list);
        return res;
        
            
    }
    
    public void f(int sum, int index,int[] num, ArrayList<Integer> list){
        //递归终止条件:sum值为0 即找到一个解;或者超过了预期的sum 或者到了num的边界
        if(sum==0){
            res.add(new ArrayList(list));
            return;
        }
        if(sum<0||index==num.length)
            return;
        
        
        sum-=num[index];
        list.add(num[index]);
        f(sum, index, num, list);
        

        //相当于回退 当前计算中 把inde为下标的数字刨除 从index+1开始计算值为sum的组合
        sum+=num[index];
        list.remove(list.size()-1);
        f(sum,index+1,num,list);
 
        
    }
}

三:二维平面上使用回溯

题目描述:word search

class Solution {
    int[][] step={{-1,0},{0,1},{1,0},{0,-1}};//用于在四个方向上的位移的辅助数组
    
    public boolean exist(char[][] board, String word) {
        //利用回溯的思想
        int m=board.length;
        int n=board[0].length;
        boolean[][] visited=new boolean[m][n];
        
        for(int i=0; i<m; i++){
            for(int j=0; j<n; j++){
                if(search(board,word,0,i,j,visited))
                    return true;
            }
        }
        
        return false;       
    }
    
    //在board中寻找word,从startx startY的位置寻找word的下标为index的字符
    public boolean search(char[][] board, String word, int index, int startX, int startY,boolean[][] visited){
        //递归终止条件,即当搜索到了word的最后一位时,检查当前所在位置是否与最后一位的字符相等
        if(index==word.length()-1)
            return board[startX][startY]==word.charAt(index);
        
        //递归过程 如果当前位置符合条件 则递归搜索其周围四个位置上是否有下一个位的字符
        if(board[startX][startY]==word.charAt(index)){
            visited[startX][startY]=true;
            for(int k=0; k<4; k++){
                int newX=startX+step[k][0];
                int newY=startY+step[k][1];
                //下一步的位置没越界且未被访问过 且值为word下一位的值
                if(inArea(newX,newY,board)==true && visited[newX][newY]==false && search(board,word,index+1,newX,newY,visited))
                    return true;
            }
            visited[startX][startY]=false;//回溯 
        }
        //当前位置就不行 则本次函数直接返回false
        return false;
    }
    
    //判断是否越界的函数
    public boolean inArea(int x,int y,char[][] board){
        return x>=0 && x<board.length && y>=0 && y<board[0].length;
    }
}

 

四:经典问题:floodfill

题目描述:岛屿的个数

给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:
11110
11010
11000
00000

输出: 1

示例 2:

输入:
11000
11000
00100
00011

输出: 3
class Solution {
    int[][] d={{1,0},{0,1},{0,-1},{-1,0}};//向四个方向的位移
    int count=0;
    
    public int numIslands(char[][] grid) {
        
        if(grid==null)
            return 0;
        //floodfill问题
        int m=grid.length;
        int n=0;
        
        if(m>0)
            n=grid[0].length;
        
        boolean[][] visited=new boolean[m][n];//用来标识某一位是否已经被标记过的数组
        for(int i=0; i<m ;i++){
            for(int j=0; j<n; j++){
                if(grid[i][j]=='1' && visited[i][j]==false){
                  count++;
                  f(grid,i,j,visited);
                }

            }
        }
        
        return count;
        
        
    }
    //标记从startX startY位置周围四个位置的数字的函数,如果是岛屿 就标记visited为true
    public void f(char[][] grid, int startX, int startY, boolean[][] visited){
        visited[startX][startY]=true;
        for(int i=0; i<4; i++){
            int newX=startX+d[i][0];
            int newY=startY+d[i][1];
            //如果下一个位置未被访问 且未越界 且是岛屿 则递归对其周围元素进行标记
            if(inArea(newX,newY,grid)==true && visited[newX][newY]==false && grid[newX][newY]=='1'){
                f(grid, newX, newY, visited);
            }
            //因为即使退出函数 也不用对标记过的数字进行回退 所以这里不用做什么
            
        }
    }
    
    public boolean inArea(int x, int y, char[][] grid){
        return x>=0 && x<grid.length && y>=0 && y<grid[0].length;
    }
    
}

题目描述:surrouded regions:

Given a 2D board containing'X'and'O', capture all regions surrounded by'X'.

A region is captured by flipping all'O's into'X's in that surrounded region .

For example,

X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:

X X X X
X X X X
X X X X
X O X X
public class Solution {
    int[][] d={{1,0},{0,1},{-1,0},{0,-1}};//向四个方向进行位移的数组
    public void solve(char[][] board) {
        //floodfill问题 与计算岛屿个数那道题差不多 思路是找到不被包围的位置进行标记
        //标记是否要被翻转的二维数组
       
        if(board==null)
            return;
        int m=board.length;
        int n=0;
        if(m>0)
            n=board[0].length;
        
        boolean[][] label=new boolean[m][n];
        //被翻转的O一定在边界 或者与边界的O直接或间接地相连
        //以边界的O为突破口 将一定不能被翻转的O标记上 然后把剩余的O翻转
        //第一列
        for(int i=0; i<m; i++){
            if(board[i][0]=='O'){
                f(board,i,0,label);
            } 
        }
        //第一行
        for(int i=0; i<n; i++){
             if(board[0][i]=='O'){
                f(board,0,i,label);
            }  
        }
        //最后一列
        for(int i=1; i<m; i++){
             if(board[i][n-1]=='O'){
                f(board,i,n-1,label);
            }  
        }
        //最后一行
       for(int i=1; i<n; i++){
             if(board[m-1][i]=='O'){
                f(board,m-1,i,label);
            }  
        }
        
        //标记完成 进行翻转
        for(int i=0; i<m; i++)
            for(int j=0; j<n; j++){
                if(label[i][j]==false && board[i][j]=='O')
                    board[i][j]='X';
            }
        
    }
    
    public void f(char[][] board, int startX, int startY,boolean[][] label){
        label[startX][startY]=true;//标记当前位置
        for(int i=0; i<4; i++){
            int newX=startX+d[i][0];
            int newY=startY+d[i][1];
            if(inArea(newX,newY,board)==true && board[newX][newY]=='O' && label[newX][newY]==false){
                f(board, newX, newY,label);
            }
        }
    }
    
    public boolean inArea(int x, int y, char[][] board){
        return x>=0 && x<board.length && y>=0 && y<board[0].length;
    }
}

五:N-Queens问题:

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值