最长对称字符串php_专题系列——字符串

本文精选了LeetCode上的几道经典算法题,包括有效字母异位词验证、最长回文串查找、同构字符串判断、回文数识别及二进制子串计数等,通过详细的代码实现和思路讲解,帮助读者掌握算法设计技巧。

c7f69948b855f9af29a4422d80f3839c.png

一、LeetCode242. 有效的字母异位词

长度不相等直接返回false,然后用一个哈希表存储即可,一开始初始化为0,然后遍历s的时候加一,遍历t的时候减一,这样如果s和t的字符都是一样的,哈希表最后还是0,否则就不是字母异位词。

这里一个点是,因为字符可以直接转化为数字,所以可以直接做下标,之前我本来想用哈希表的。。直接用数组存储会简单很多。

class Solution {
public:
    bool isAnagram(string s, string t) {
        // 因为字符可以转化为数字,所以可以直接变为下标数字,都初始化为0
        if(s.size()!=t.size()) return false;
        vector<int> temp(26, 0);
        for(int i = 0; i < t.size(); i++){
           temp[s[i] - 'a']++;
           temp[t[i] - 'a']--;
        }
        for(int i = 0; i < 26; i++){
            if(temp[i] != 0) return false;
        }
        return true;
    }
};

二、LeetCode409. 最长回文串

回文串,长度如果是偶数,那所有字母都是成对出现,长度如果是奇数,那就再加上一个单个字符作为对称中心。所以就变成了统计有多少个成对出现的字母,以及如果有奇数出现的字母,就给回文串加上一个对称中心。

利用第一个题的思路,就是利用哈希表存储,每个字符出现的次数,然后出现的偶数次都加到回文串的长度中,这里有一个需要注意的点是有大写字母的存在,因为在存储的时候就不再是26个哈希长度,而是52个哈希长度了。

class Solution {
public:
    int longestPalindrome(string s) {
        // 用一个哈希表把字符出现次数存储起来,之后遍历哈希表,把偶数次出现的和奇数次出现的次数都存起来,然后最后就是偶数次数加上一个奇数次
        vector<int> temp(52, 0);
        int even = 0, odds = 0;
        for(int i = 0; i < s.size(); i++) {
            if(isupper(s[i])) temp[26 + s[i] - 'A']++;
            else temp[s[i] - 'a']++;
        }
        for(int i = 0; i < 52; i++){
            even += 2 * (temp[i] / 2);
            odds += temp[i] % 2;
        }
        return odds > 0 ? 1 + even : even;   
    }
};

三、LeetCode 205. 同构字符串

用一个map存储s到t的映射,也就是map[s] = t,把s中的字符都换成哈希表map[s]中的对应的t的字符,如果最后赋值完毕以后,s和t是一样的,那就是同构的,否则就不是同构的。这里有一个需要注意的点是,这样一次遍历是s到t的映射,但是t到s的映射也需要考虑,否则下面这样样例就不可以通过

s = "ego",t = "add"

这里我设置了一个set来存储t中已经被映射过的字符,如果是set中存在了当前的t[i],那就说明之前已经有s的字符和t[i]对应了,那这个肯定不是一个同构的字符,就直接返回false就可以了。然后如果题目要求不可以改变s的话,就按照方法2,判断map就好了,只是方法一的运行时间比较快一点。

方法一:改变s的值

class Solution {
public:
    bool isIsomorphic(string s, string t) {
        // 遍历s和t,用一个哈希表映射,s的字符用t的字符替换,如果替换完毕以后的s和t是一样的,那就说明是同构的,否则就不是同构的。同时是
        if(s.size() != t.size()) return false;
        map<char, char> temp;
        set<char> set;
        for(int i = 0; i < s.size(); i++){
            if(temp.find(s[i]) == temp.end()) {
                if(set.find(t[i]) != set.end()) return false;
                set.insert(t[i]);
                temp[s[i]] = t[i];
            }
            s[i] = temp[s[i]];
        }
        if(s == t)  return true;
        return false;
        
    }
};

方法二:不改变s的值

class Solution {
public:
    bool isIsomorphic(string s, string t) {
        // 遍历s和t,用一个哈希表映射,s的字符用t的字符替换,如果替换完毕以后的s和t是一样的,那就说明是同构的,否则就不是同构的。同时设置一个set,保证t的映射也是唯一的
        if(s.size() != t.size()) return false;
        map<char, char> temp;
        set<char> set;
        for(int i = 0; i < s.size(); i++){
            if(temp.find(s[i]) == temp.end()) {
                if(set.find(t[i]) != set.end()) return false;
                set.insert(t[i]);
                temp[s[i]] = t[i];
            }else{
                if(temp[s[i]] != t[i]) return false;
            }
        }
        return true;
        
    }
};

四、9. 回文数

方法一:将数字转化为字符串,比较简单粗暴

class Solution {
public:
    bool isPalindrome(int x) {
        // 转为字符串,然后双指针对比就可
        if(x < 0) return false;
        string s = to_string(x);
        for(int i = 0, j = s.size() - 1; i < s.size() / 2 + 1; i++, j--){
            if(s[i] != s[j]) return false;
        }
        return true;
    }
};

方法二:

将数字的后面一半反转,比较反转后的数字和数字的前面部分是否相等。这里需要考虑奇数和偶数,如果是长度是偶数,那比较简单,就是相等那就是回文数,如果长度是奇数,那就前面的部分除以10以后,再与后面反转的数字比较,相等就是回文数

但这里要特判10的倍数,因为这里如果后面一直是0的话,会出现lastnums一直是0的情况,就会一直小于x,直到x为0,这样最后x和last_nnus就都是0,算法就返回true,但是其实不是的。

class Solution {
public:
    bool isPalindrome(int x) {
        if(x < 0 || x % 10 == 0 && x != 0) return false;
        int last_nums = 0;
        while(last_nums < x){
            last_nums = last_nums * 10 + x % 10;
            x /= 10;
        }
        return x == last_nums || x  == last_nums / 10;
    }
};

五、696. 计数二进制子串

// 0和1都是连续的,所以就从头开始遍历,计算某个字符0的个数,然后遇到另外一个字符1的时候,保存下上一个的字符0的长度,之后1的字符长度开始计数,如果0的长度是大于1的长度,那子串的个数就加一,【就比如0001111这种情况,就有3个子串01,0011,000111这三个】

class Solution {
public:
    int countBinarySubstrings(string s) {
        int curlen = 1, prelen = 0, ret_num = 0;
        for(int i = 1; i < s.size(); i++){
            if(s[i] == s[i - 1]) curlen++;
            else{
                prelen = curlen;
                curlen = 1;
            }
            if(prelen >= curlen) ret_num++;
        }
        return ret_num;
    }
};

六、LeetCode 647. 回文子串

中心法则,检测回文子串是非常棒棒的解法了。懒得看dp了。。

class Solution {
public:
    int countSubstrings(string s) {
        // 中心法则,从中心开始检测回文串
        int ret = 0;
        for(int i = 0; i < s.size(); i++){
            ret += countSubstrings2(s, i, i);
            ret += countSubstrings2(s, i, i + 1);
        }
        return ret;
    }
    int countSubstrings2(string s, int left, int right){
        int count = 0;
        while(left >= 0 && right < s.size() && s[left--] == s[right++]){
            count++;
        }
        return count;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值