穷举&&深搜&&暴搜&&回溯&&剪枝(4)

一)单词搜索:

直接在矩阵中依次找到特定字符串

79. 单词搜索 - 力扣(LeetCode)

画出决策树,只需要做一个深度优先遍历:

穷举&&深搜&&暴搜&&回溯&&剪枝(4)_第1张图片

穷举&&深搜&&暴搜&&回溯&&剪枝(4)_第2张图片

1)设计dfs函数:只需要关心每一层在做什么即可,从这个节点开始,开始去尝试匹配字符串的下一个字符,就是从某一个位置的字符开始,上下左右下标看看能不能匹配下一个字符给定一个节点的位置,上下左右去匹配一个结点的位置,dfs(char[][] board,i,j,s,pos),把原始的矩阵给定,把这个字符的位置,把要匹配字符串,字符串匹配到哪一个位置

2)从i,j位置开始上下左右去搜索word的哪一个字符就可以了

3)boolean返回值代表此次路径的选择是成功还是失败

穷举&&深搜&&暴搜&&回溯&&剪枝(4)_第3张图片

2)二维矩阵中要注意的细节问题:

在二维矩阵搜索的过程中不能走重复的路,要想解决这个问题,可以有两种方法:

2.1)使用一个和原始矩阵相同规模大小的布尔数组,如果这个字符已经被路径走过了,那么直接修改成true

2.2)直接修改原始矩阵的值,如果某一个字符被走过了,那么直接修改字符为.或者其他标记字符

假设在下面的这个例子中给定我们一个矩阵,给定一个字符串A="AAAA"判断是否可以匹配成功

穷举&&深搜&&暴搜&&回溯&&剪枝(4)_第4张图片

2.3)当我们第一次成功的匹配到了A字符的时候,将这个A字符标记成true,表示这个字符已经被使用过了,此时想左匹配第二个A字符,当尝试在第二个A字符中匹配第三个A字符的时候,此时是不能再继续想左找第一个A字符了,此时因为第一个A字符已经被使用过了

class Solution {
    public boolean[][] check;
    int row;
    int col;
//利用向量数组一个for循环搞定上下左右四个方向
    int[] dx={0,0,1,-1};
    int[] dy={1,-1,0,0};
 public boolean dfs(char[][] board,String word,int i,int j,int pos){
        if(pos==word.length()) return true;
        //当匹配到最后一个字符之后直接返回
        //接下来向上下走有去匹配word[pos];
        for(int k=0;k<4;k++){
//从这里面开始左每一层所做的事情,从(i,j)下标开始上下左右去匹配pos位置的字符
            int x=i+dx[k];
            int y=j+dy[k];
if(x>=0&&x=0&&y

二)黄金矿工:

算法原理:

1)这个题和上一个题的起始dfs位置是存在着差别的,上一道题必须是从字符串的第一个位置开始才可以进行向下dfs,而这个题从上下左右边界任意位置开始进行dfs都可以

2)开采过的位置不能再挖,0号位置不能再挖

3)枚举所有位置为起点,进行爆搜

1219. 黄金矿工 - 力扣(LeetCode)

class Solution {
    int ret=0;
    int row=0;
    int col=0;
    public boolean[][] check;
    int[] dx={0,0,1,-1};
    int[] dy={1,-1,0,0};
    public void dfs(int[][] array,int i,int j,int glod){
        glod+=array[i][j];
        ret=Math.max(glod,ret);
        for(int k=0;k<4;k++){
            int x=i+dx[k];
            int y=j+dy[k];
if(x>=0&&x=0&&y

三)不同路径

算法原理:在矩阵中进行搜索,先找到1的位置,从这个起始位置开始进行深度优先遍历,然后进行判断这条路径是否合法即可,解决方法就是在进行向下递归的过程中使用count变量来记录一下,从起始位置开始记录一下行走步数,到达最终结果之后,再进行对比和实际要走的步数是否相同(整个数组0的个数)

980. 不同路径 III - 力扣(LeetCode)

class Solution {
    //这样处理的目的就是我所走的所有路径的格子数等于总的格子数
    public int step=2;//表示处理第一个数和最后一个数
    public boolean[][] check;
    public int row=0;
    public int col=0;
    public int count=1;//表示处理第一个数
    public int ret=0;
    int[] dx={0,0,1,-1};
    int[] dy={1,-1,0,0};
    public void dfs(int[][] array,int i,int j){
        if(array[i][j]==2){
            if(step==count){
                System.out.println(ret);
               ret++;
            }
         return;
        }
        for(int k=0;k<4;k++){
            int x=i+dx[k];
            int y=j+dy[k];
if(x>=0&&x=0&&y

四)递增子序列

算法原理:

1)这个题的剪枝策略一共有两步:

1.2)在同一层内,相同的元素重复出现的要剪掉

1.3)在每一层内进行枚举,从pos+1的位置开始进行枚举,防止使用到上一层已经使用过的元素

1.3)在本层进行枚举元素的时候,一定要比上一层的最后一个元素要大,但是如果path中没有任何元素,那么就可以放心地向里面添加元素

491. 递增子序列 - 力扣(LeetCode)

class Solution {
    List> ret=new ArrayList<>();
    List path=new ArrayList<>();
    public void dfs(int[] nums,int pos){
        if(path.size()>=2){
            ret.add(new ArrayList<>(path));
        }
HashSet set=new HashSet<>();
//将本层的所有元素保存起来,防止重复
        for(int i=pos;i> findSubsequences(int[] nums) {
        dfs(nums,0);
        return ret;
    }
}

五)分割回文串

131. 分割回文串 - 力扣(LeetCode)

1)什么是切割线?startIndex后面应该被切割的字符串的第一个位置,第一个分割线就是在startIndex第一个字符后面的

2)如何表示切割的子串的范围?[startIndex,i],i一开始等于startIndex,此时切割线在i所指向的字符的后面

穷举&&深搜&&暴搜&&回溯&&剪枝(4)_第5张图片

class Solution {
    List> ret=new ArrayList<>();
     boolean[][] dp=null;
    List path=new ArrayList<>();
    public void dfs(String s,int startIndex){
        if(startIndex==s.length()){
            ret.add(new ArrayList<>(path));
            return;
        }
//注意单层递归的逻辑
        for(int i=startIndex;i> partition(String s) {
//1.首先创建一个dp表,dp[i][j]表示以i位置元素为起点,j位置字符为终点,是否这个子串是一个回文串
this.dp=new boolean[s.length()][s.length()];
 //从下到上,从走向右进行填表
    for(int i=s.length()-1;i>=0;i--){
         for(int j=i;j

六)复原IP地址

93. 复原 IP 地址 - 力扣(LeetCode)

算法原理:

1)什么是有效的IP地址呢?

1.1)首先这个IP地址的经过逗号分割的单独一个部分可以包含一个0,但是一个数字前面不能出现前导0,就比如说0.011.122.32

1.2)还有经过逗号分割的每一个部分的值都是小于255的,例如192.168.1.455

1.3)如果给定的字符串中出现了非正整数字符的话,那么它本身也是一个非法的IP地址

所以本题我们不光要对字符串进行切割处理,还需要针对切割出来的每一个字符串要做一个合法性的判断

你可能感兴趣的:(剪枝,linux,算法)