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

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绕着绕着把自己绕晕了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值