算法学习(九):回溯算法

目录

一、leetcode 17. 电话号码的字母组合

二、剑指offer 64.矩阵中的路径

三、剑指offer 65.机器人的运动范围


一、基本概念

一个函数在进行递归调用时,总是从一个入口进去,并逐级深入,直到到达递归终止条件并逐级返回。在这个返回的过程中做出一些操作,就是回溯。

在leetcode第17题中,就可以使用回溯算法快速解决,下面给出题目和解答。

一、leetcode 17. 电话号码的字母组合

leetcode 17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
*************************
1:     2:abc  3:def
4:ghi  5:jkl  6:mno
7:pqrs 8:tuv  9:wxyz
*************************
示例:

输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

三、代码及注释

package IMUHERO;
import java.util.ArrayList;
import java.util.List;

public class Solution17_backstracking {
    private String letterMap[] = {
            " ",    //0
            "",     //1
            "abc",  //2
            "def",  //3
            "ghi",  //4
            "jkl",  //5
            "mno",  //6
            "pqrs", //7
            "tuv",  //8
            "wxyz"  //9
    };

    private ArrayList<String> res;

    public List<String> letterCombinations(String digits) {

        res = new ArrayList<String>();
        if(digits.equals(""))
            return res;

        findCombination(digits, 0, "");
        return res;
    }

    // s中保存了此时从digits[0...index-1]翻译得到的一个字母字符串
    // 寻找和digits[index]匹配的字母, 获得digits[0...index]翻译得到的解
    private void findCombination(String digits, int index, String s){

        
        if(index == digits.length()){
            res.add(s);
            return;
        }
        Character c = digits.charAt(index);
        String letters = letterMap[c - '0'];//注意:此处要c-'0'才是数字,‘c’不是数字
        for(int i = 0 ; i < letters.length() ; i ++){
            findCombination(digits, index+1, s + letters.charAt(i));
        }
        return;
    }
    //以下内容两部分是测试函数***********************************************
    private static void printList(List<String> list){
        for(String s: list)
            System.out.println(s);
    }

    public static void main(String[] args) {

        printList((new Solution17_backstracking()).letterCombinations("234"));
    }
}

四、简单分析

1.回溯的思想体现在:

按下按键 2 ,包含的字符为“abc” 

按下按键 3 ,包含的字符为“def”

按下按键 4 ,包含的字符为“ghi ”

通过代码中的for循环,首先遍历到a

递归进入下一层:首先遍历到d

递归进入下一层:首先遍历到h

达到递归终止条件!添加此种可能到结果(“adg”)

return

返回上一层:h已经遍历过了,接下去遍历i,将i添加到“ad”字符串的末尾

形成一种新的结果:“adh”

同理,继续形成"adi"。

->>至此按键4部分的三个字符都已经遍历完,return

->>来到按键3,d已经遍历过了,现在遍历e,添加到“a”字符串末尾,形成“ae”

//重复按键四的三个字符遍历,形成“aeg”、“aeh”、“aei”

依次类推。。。。。。。。直到求出所有结果

/**************************************************************************************************************/

测试函数的测试结果如下:(与推理结果一致)

adg
adh
adi
aeg
aeh
aei
afg
afh
afi
bdg
bdh
bdi
beg
beh
bei
bfg
bfh
bfi
cdg
cdh
cdi
ceg
ceh
cei
cfg
cfh
cfi

二、剑指offer 64.矩阵中的路径

 1.题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。
如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。
 例如 a b c e s f c s a d e e 矩阵中包含一条字符串"bccced"的路径,但是矩阵中不包含"abcb"路径,
 因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

2.分析:

 1.两层循环是用来遍历所有情况的,只要有一条路径,就返回true。而不能直接返回
2.排除完所有false的情况,剩余的情况就为true
3.if (len==str.length-1){
            return true;
        }
4.如果所有情况都不为true,则需要修改isVisited的值

package IMUHERO;

public class Sword_64_Path_in_rectangle {
    boolean [] isVisited;
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {
        isVisited = new boolean[matrix.length];    //初始默认为false
        for(int i=0;i<rows;i++){
            for (int j =0;j<cols;j++){
                if (findPath(matrix, i, j, rows, cols, str,0)) {
                    return true;
                }
            }
        }
        return false;
    }
    private boolean findPath(char[]matrix,int i,int j,int rows,int cols,char[]str,int len){
        int index = i*cols+j;   //当前遍历到的元素在一维数组中存储的位置


        if (i<0||j<0||i>=rows||j>=cols||isVisited[index]==true||str[len]!=matrix[index]){
            return false;
        }

        if (len==str.length-1){
            return true;
        }
        isVisited[index]=true;
        if (findPath(matrix,i-1,j,rows,cols,str,len+1)||
                findPath(matrix,i,j+1,rows,cols,str,len+1)||
                findPath(matrix,i+1,j,rows,cols,str,len+1)||
                findPath(matrix,i,j-1,rows,cols,str,len+1)){
            return true;
        }

        isVisited[index]=false;
        return false;
    }

}

三、剑指offer 65.机器人的运动范围

1.题目描述
地上有一个m行和n列的方格。
一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,
但是不能进入行坐标和列坐标的数位之和大于k的格子。 
例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。
但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

2.分析

1.使用count计算走过可行的格子数,使用isVisited判断是否已经走过。

2.judge是辅助函数,用来将横坐标和纵坐标的位值相加,并判断是否超过阈值:threshold。

3.递归函数,递归终止条件是所有不可行的情况:越界、位值超过阈值、或者isVisited。

4.如果可行,要将isVisited标志位设为true,这里与上一题不同就在于:走过的路无需将isVisited重新设为false

5.每次可行都累加count,最终所有格子上下左右都走不通,返回原函数,并返回count的值。

public class Solution {
    int count;
    boolean [][] isVisited;
    public int movingCount(int threshold, int rows, int cols)
    {
        isVisited = new boolean [rows][cols];
        movingCount( 0 , 0 , threshold , rows , cols );
        return count;
    }
    
    private void movingCount(int i,int j ,int threshold,int row ,int cols){
        if(i<0||i>=row||j<0||j>=cols||!judge(i,j,threshold)||isVisited[i][j])return;
        count++;
        isVisited[i][j]=true;
        movingCount(i-1,j,threshold,row,cols);
        movingCount(i,j+1,threshold,row,cols);
        movingCount(i+1,j,threshold,row,cols);
        movingCount(i,j-1,threshold,row,cols);
        return;
    }
    
    private boolean judge(int x,int y,int k){
        int count=0;
        while(x!=0){
            count+=x%10;
            x/=10;
        }
        while(y!=0){
            count+=y%10;
            y/=10;
        }
        if(count>k)return false;
        else return true;
    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IMUHERO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值