迭代:从上到下来做一件事情,for循环就是迭代的一种。

递归:一般我们认为递归就是迭代的一种。可以重复一直做一件事,直到达到某种条件时,跳出递归。递归的核心思想  1.先找递归出口  2.每次递归方法要做什么。

回溯:其实回溯和递归很相似,都是重复做一件事,区别就是在递归的方法前加“增加操作“,方法后”相应减操作“

为了更快的了解区别,还是需要例子。LeetCode题

17. 电话号码的字母组合

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

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

回复迭代器java 迭代回溯算法_git

解法思路

  • 这是个排列组合问题对吧?这个排列组合可以用树的形式表示出来;
  • 当给定了输入字符串,比如:"23",那么整棵树就构建完成了,如下:

    

回复迭代器java 迭代回溯算法_递归_02

从上面图来看我们可以分成两步骤来解决问题:1. 先找数字。2.从数字对应的字母数组中找字母。3.重复步骤1,2。

这样看来我们可以用迭代方法,也可以用递归和回溯来解决问题。但迭代用起来相对复杂,比较乱。

方法1:递归

class Solution {
     private String[] letterMap= {
            " ",    //0
            "",     //1
            "abc",  //2
            "def",  //3
            "ghi",  //4
            "jkl",  //5
            "mno",  //6
            "pqrs", //7
            "tuv",  //8
            "wxyz"  //9
    };
    ///用迭代法思路很混乱,1.选数字 2.选数字中的字母,3 重复1.2步骤
    ///可以用递归来解决,每次先选数字,然后再选字母
    List<String> lists = new ArrayList<>();
    private int slen;
    public List<String> letterCombinations(String digits) {
        slen = digits.length();
        if(slen == 0) return lists;
        char[] ch = digits.toCharArray();
        dfsLetter(ch, 0, "");
        return lists;
    }
    private void dfsLetter(char[] digits, int path, String comLetter){
        if(slen == path){//当前路径已经触底,所以把此组合放进数组中
            lists.add(comLetter);
            return ;
        }//digits[path]表示当前的数字,通过数字知道当前数字包含的字母长度
        String str = letterMap[digits[path]-'0'];
        for(int i=0;i<str.length();i++)
        //递归的关键,每次路径加1便增加一个字符
        dfsLetter(digits, path+1, comLetter + str.charAt(i));
    }
}

 注意:26行是递归的出口,递归的核心思想  1.先找递归出口  2.每次递归方法要做什么。

33行 每次递归的目的就是增加路径深度path,添加一个字符str.charAt(i);

但时间复杂度很不理想,原因是String 用 + 来拼接牺牲了内存和时间,可以用回溯来优化

方法2 回溯

 

class Solution {
     private String[] letterMap= {
            " ",    //0
            "",     //1
            "abc",  //2
            "def",  //3
            "ghi",  //4
            "jkl",  //5
            "mno",  //6
            "pqrs", //7
            "tuv",  //8
            "wxyz"  //9
    };
    ///用迭代法思路很混乱,1.选数字 2.选数字中的字母,3 在次选数字,4选数字中的字母,重复1.2步骤
    ///可以用递归来解决,每次先选数字,然后再选字母
    List<String> lists = new ArrayList<>();
    private int slen;
    public List<String> letterCombinations(String digits) {
        slen = digits.length();
        if(slen == 0) return lists;
        char[] ch = digits.toCharArray();
        dfsLetter(ch, 0, new StringBuilder());
        return lists;
    }
    private void dfsLetter(char[] digits, int path, StringBuilder sb){
        if(slen == path){
            lists.add(sb.toString());
            return ;
        }//digits[path]表示当前的数字,通过数字知道当前数字包含的字母长度
        String str = letterMap[digits[path]-'0'];
        for(int i=0;i<str.length();i++){
            sb.append(str.charAt(i));//递归之前添加一个字符
            dfsLetter(digits, path+1, sb);
            sb.deleteCharAt(path);//递归后剪掉一个字符
        }
        
    }
}

 回溯的核心我觉得在32行和34行

时间复杂度如下所示:

回复迭代器java 迭代回溯算法_迭代_03