用7-4 的递归思路实现Letter Combination,为什么会更慢?

来源:8-2 什么是回溯

shanmufeng

2017-08-04

老师,我根据7-4定义递归问题 BinaryTreePath 的递归思路实现Letter Combination,变慢了,不知道是我的实现问题还是算法本身确实比较慢?

我的思路: 比如digits="234", 在"34"返回的所有string前都加 “a”,“b”or “c”,再返回新的vector<string>。 如果是最后一个digits,则返回最后一个digit对应的几个字母。按照这个思路,可以减少了重复访问 “3”和“4”的次数,我觉得是更快的。

以下是我的code,在leetcode通过,3ms(课程实现代码0ms,怎么这么快,超越不了了=_=)

class Solution {
private:
    const string letterMap[10] = {
            " ",    //0
            "",     //1
            "abc",  //2
            "def",  //3
            "ghi",  //4
            "jkl",  //5
            "mno",  //6
            "pqrs", //7
            "tuv",  //8
            "wxyz"  //9
    };

    vector<string> findCombination(string digits,int index){
        vector<string> res;

        //for last index, return s[digits[digits.size()-1]]
        if(index==digits.size()-1) {
            char c = digits[index];
            assert(c>='0'&&c<='9'&&c!='1');
            string letters = letterMap[c-'0'];
            for(int i=0;i<letters.size();i++) {
                string s1(1, letters[i]);
                res.push_back(s1);
            }
            return res;
        }

        // add s[digits[index]] to s[digits[0...index-1]]
        char c = digits[index];
        assert(c>='0'&&c<='9'&&c!='1');
        string letters = letterMap[c-'0'];
        vector<string> s = findCombination(digits, index+1);
        for(int i=0;i<letters.size();i++){
            for(int j=0;j<s.size();j++){
                string s1(1, letters[i]);
                string newS = s1 + s[j];
                cout<<"get "<<newS<<endl;
                res.push_back(newS);
            }
        }
        return res;
    }

public:
    vector<string> letterCombinations(string digits) {
        vector<string> res;
        if(digits=="")
            return res;

        res = findCombination(digits,0);

        return res;

    }
};


写回答

1回答

liuyubobobo

2017-08-05

首先,算法复杂度是一样的。你说的减少“3”和“4”的访问次数是不存在的。我的方法是从左向右生成字符串,你的方法实质上是从右向左生成字符串。你的方法是在"34"返回的所有string前都加 “a”,“b”or “c”;我的方法是在“23”得到的所有string后面加 “g”,“h”or “i”。如果你说减少了重复访问“34”结尾的情况,那我的方法就是减少了重复访问“23”开头的情况。事实上,这两种方式都是将每种情况做遍历,顺序不同而已,复杂性分析是一致的:)


但你的实现显然比我的实现处理了更多的内容,比如在findCombination中开辟了更多的string类型并且进行操作;同时维护s也是有成本的(每次返回res,都相当于又制造了一个res的副本!并且当digits长的时候,res会很大,在每一层递归都要记录维护这个很大的数组。)。仔细体会我的实现,res使用类中的成员变量,对于整个算法来说相当于是使用了全局变量:)


但其实你的思路其实完全可以根据我的代码结构做修改,把从左往右生成结果的方式修改成从右往左生成,感兴趣可以试试看:)


1
3
liuyubobobo
回复
shanmufeng
赞思考!你说的非常对!仔细想,其实在我的实现中,中间变量也已经通过参数传给下一层,并且这个传输过程的冗余度是很低的:)
2017-08-06
共3条回复

玩转算法面试-- Leetcode真题分门别类讲解

课程配套大量BAT面试真题,高频算法题解析,强化训练

7410 学习 · 1150 问题

查看课程