LintCode解题记录17.8.9 字符串处理5

来源:互联网 发布:智慧城市业务数据库 编辑:程序博客网 时间:2024/06/05 14:43

LintCode Binary Representation

给定一个数(包含小数),返回其二进制形式。如果小数点后的二
进制位大于32位,则返回ERROR。
思路
整数部分转化为二进制是模2取余,小数部分是乘2取整。
代码

    string binaryRepresentation(string n) {        // wirte your code here        int l = n.size();        int split = n.find('.');        int former = atoi(n.substr(0, split).c_str());        double latter = atof(n.substr(split).c_str());        //get the former interger and latter fractional part.        string res = "";        if (former == 0) res += '0';        while (former) {            res += former%2 + '0';            former /= 2;        }        reverse(res.begin(), res.end());        int cnt = 0;        if (latter) res += '.';        while (latter && cnt < 32) {            latter *= 2;            res += latter >= 1? '1' : '0';            if (latter >= 1) latter--;            cnt++;        }        return cnt == 32 ? "ERROR" : res;    }

总结
1.C/C++分割字符串
在本题中体现在将给定字符串以小数点分割,分成整数部分和小数部分。
四种方法,第一种用C库的strtok函数,函数原型为 char *strtok(char *str, const char *delim);str是要分割的字符串,delim是分割的字符串,strtok函数在遍历str的过程中如果遍历到delim则会将其修改为’/0’。
简单应用:

    char str[] = "Hello,World,Ni,Hao.";    char *delim = ",";    //在第一次调用时,strtok()必需给予参数str字符串,往后的调用则将参数str设置成NULL。每次调用成功则返回下一个分割后的字符串指针。     char *p = strtok(str, delim);    while (p != NULL) {        printf("%s\n", p);        p = strtok(NULL, delim);    }

第二种方法是C++ STL库的find函数和substr函数。
贴官网的函数解释:
http://www.cplusplus.com/reference/string/string/find/
http://www.cplusplus.com/reference/string/string/substr/

第三种是C++IO类的stringstream
利用getline函数读取,istream& getline(istream &in, string str, char delim)

第四种是Boost库提供了split函数,我也很少用到Boost库,这里就简单提一下吧。

2.取整
在本题的体现是处理小数部分时,虽然做题的时候没有用。
可以看一下这个http://www.cnblogs.com/zjutlitao/p/3558218.html

3.字符串转整数,转双精度
atoi函数和atof函数。开头的a是ASCII码的意思。需要掌握这两种函数的具体实现,因为面试可能会问到。itoa不推荐使用。
http://blog.csdn.net/lanzhihui_10086/article/details/39989841

LintCode Regular Expression Matching

给定两个字符串,问你他们是不是匹配的正则表达式(假设正则表达式只支持.和*这两种符号)
思路1
两种思路递归和动态规划。
首先来说说递归,基本思路就是看字符串s从i位开始和字符串p从j位开始的子字符串是否匹配,递归遍历到串的末尾,最后回溯结果。假设当前位于字符串s的第i位,字符串p的第j位,那么可以分为两种情况考虑:
(1) p[j+1] != ‘*’;
这一种情况比较简单,只需要判断s[i] == p[j]即可(如果p[j] == ‘.’也代表相等)。如果不相等,则返回False,否则,递归遍历i+1位和j+1位。
(2) p[j+1] == ‘*’;
在这种条件下,匹配的情况有哪几种呢?由于*的意思是该符号前面的字符可以取0次,1次..很多次,也就是说匹配的情况就有前面的字符取了0次,取了1次,取了2次..,在这里面的一种情况实现匹配。如果取了0次,那么下一次递推就是从第i位和第j+2位开始(跳过了p上的’*’和前一字符),如果取了1次,那么下一次递推就是从第i+1位和第j+2位开始,以此类推,直到s上的第i+k位不等于p[j]位(也就是不等于’*’的前一字符)。
举个例子,假设s=”aaaab”,p=”a*b”,i=1,p=1。
因为p[1] == ‘*’,按照上面的思考就是分情况考虑。取了0次,意思就是如果s[1:]和p[2:]匹配的话,那么s[1:]一定和p[0:]匹配,反之亦然。取了1次,意思就是如果s[2:]和p[2:]匹配的话,那么s[1:]一定和p[0:]匹配。
代码

    bool isMatch(const char *s, const char *p) {        string s1(s), p1(p);        return helper(s1, p1, 0, 0);    }    bool helper(string s, string p, int i, int j) {        if (j == p.size()) return i == s.size();        if (j == p.size()-1 || p[j+1] != '*') {            if (i == s.size() || (s[i] != p[j] && p[j] != '.'))                return false;            else                return helper(s, p, i+1, j+1);        }        // p[j] == '*'        while (i < s.size() && (s[i] == p[j] || p[j] == '.')) {            if (helper(s, p, i, j+2))                return true;            i++;        }        return helper(s, p, i, j+2);    }

思路2
动态规划,不过此题的动态规划属于情况比较多比较复杂的情况了,需要仔细分析一下。
我们当然还是维护一个变量dp[i][j],表示字符串s的前i位和字符串p的前j位是否匹配。我们已知了之前所有的子状态,如何得到新的状态呢?
1) p[j-1] != ‘*’
在条件下我们有递推式
dp[i][j] = dp[i-1][j-1] if p[j-1] != ‘*’ && (s[i-1] == p[j-1] || p[j-1] == ‘.’)
2)p[j-1] == ‘*’
在这种条件下又可以分为重复0次,重复1次,重复2次,等等..
重复0次:dp[i][j] = dp[i][j-2]
重复1次: dp[i][j] = dp[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == ‘.’)
重复2次:dp[i][j] = dp[i-2][j] && ((s[i-2] == s[i-1] && s[i-1] == p[j-2]) || p[j-2] == ‘.’)
其实重复大于一次的情况都可以归结到重复1次的里面,因为你的i是顺序遍历的,会先判断dp[i-2][j]是否能匹配,如果能,才会接着考虑dp[i-1][j]能否匹配。
代码

    bool isMatch(const char *s, const char *p) {        // write your code here        string s1(s), p1(p);        int m = s1.size(), n = p1.size();        vector<vector<bool> > dp(m+1, vector<bool>(n+1, false));        dp[0][0] = true;        for (int i = 0; i <= m; i++) {            for (int j = 1; j <= n; j++) {                if (j > 1 && p1[j-1] == '*') {                    dp[i][j] = dp[i][j-2] || (i > 0 && dp[i-1][j] && (s1[i-1] == p1[j-2] || p1[j-2] == '.'));                } else                    dp[i][j] = i > 0 && dp[i-1][j-1] && (s1[i-1] == p1[j-1] || p1[j-1] == '.');            }        }        return dp[m][n];    }

感受
这道题真是绝了,自己xjb想两个多小时没做出来,看别人讲两个多小时也没看懂,自己再抄出来理解一下又花了两个多小时也迷迷糊糊。另外这道题的描述真是操蛋,没有说只有p包含了.和*,s是只有字母的字符串,不过测试用例全是这个。这下就导致自己做的时候既考虑了s又考虑了p绕着绕着把自己绕晕了。

原创粉丝点击