陆续更新字符串题目

1、 最长回文子串

暴力解题法

class Solution {
public:
    string longestPalindrome(string s) {
        string res="";//存放结果
        string temp="";//存放子串
        for(int i=0;i<s.length();i++)
        {
            for(int j=i;j<s.length();j++)
            {
                temp=temp+s[j];
                string tem=temp;//tem存放子串反转结果
                std::reverse(tem.begin(),tem.end());//反转
                if(temp==tem)
                    res=res.length()>temp.length()?res:temp;
            }
            temp="";
        }
        return res;
    }
};

中心扩展法

我们观察到回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有 2n - 1 个这样的中心。因为回文的中心要区分单双。

假如回文的中心为 双数,例如 abba,那么可以划分为 ab bb ba,对于n长度的字符串,这样的划分有 n-1 种。

假为回文的中心为 单数,例如 abcd, 那么可以划分为 a b c d, 对于n长度的字符串,这样的划分有 n 种。

class Solution {
public:
    string longestPalindrome(string s)            
    {
        if (s.length() < 1)
        {
            return "";
        }
        int start = 0, end = 0;
        for (int i = 0; i < s.length(); i++)
        {
            int len1 = expandAroundCenter(s, i, i);//一个元素为中心
            int len2 = expandAroundCenter(s, i, i + 1);//两个元素为中心
            int len = max(len1, len2);
            if (len > end - start)
            {
                start = i - (len - 1) / 2;
            //对称个数是偶数个的时候,start离i近,如abba ->0123 ->  1-3/2=0
                end = i + len / 2;
            }
        }
        return s.substr(start, end - start + 1);
    }

    int expandAroundCenter(string& s, int left, int right)
    {
        int L = left, R = right;
        while (L >= 0 && R < s.length() && s[L] == s[R])
        {// 计算以left和right为中心的回文串长度
            L--;
            R++;
        }
        return R - L - 1;
    }    
};

2、重复的DNA序列

所有 DNA 都由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。

编写一个函数来查找目标子串,目标子串的长度为 10,且在 DNA 字符串 s 中出现次数超过一次。

首先要理解题目,题目的意思是编写一个函数来查找子串,这个子串长度为10,在原字符串中出现超过一次。

思路:用哈希表关联方式,从头以长度10遍历字符串,然后放进哈希表里,如果有相同的就加1,最后输出大于一的就好。

class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) {
        int n =10;
        vector<string> res;
        if(s.size() < 10)
            return res; 
        map<string , int> m;
        for(int i = 0 ; i <= s.size() - n;i++)
        {
            m[s.substr(i,n)]++;
        }
        for(auto p:m)
        {
            if(p.second > 1)
                res.push_back(p.first);
        }
        return res;

    }
};

3. 无重复字符的最长子串

思路:采用滑窗法,并用map记录字符出现的位置,记录最大值。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.empty())
            return 0;
        map<char,int> m;
        int res = 0,left = 0; // 由于map不能初始化,所以默认为0
        for(int i=0;i<s.size();++i)
        {
            left = max(left,m[s[i]]);
            m[s[i]] = i+1; //此处记录的是第几个的位置
            res = max(res,i-left+1);//上面加1了,此处就要-1;
        }
        return res;
    }
};

4、 替换空格

用到之前总结的双指针法,注意string需要扩容。

class Solution {
public:
    string replaceSpace(string s) {
        //length属性:用于获取数组长度。
        //length属性:用于获取数组长度。
        //size()方法:用于获取泛型集合有多少个元素。
        int orginalLength = s.size() - 1;
        int numberOfBlank =0;
        for (auto c : s){
            if (c == ' ') ++numberOfBlank;
        }

        int newLength = orginalLength + numberOfBlank * 2;
        s += string(numberOfBlank * 2,' ');//扩容
        int indexOriginal = orginalLength;
        int indexNew = newLength;
        for(int i = orginalLength , j=newLength ;i<j ; i--)
        {
            if(s[i] == ' ')
                {
                    s[j--] = '0';
                    s[j--] = '2';
                    s[j--] = '%';
                }
            else
            {
                s[j--] =s[i];
            }
        }
        return s;
    }
};

5、 字符串排列

输入一个字符串,打印出该字符串中字符的所有排列。

class Solution {
public:
    vector<string> Permutation(string str)
    {
        vector<string> result;
        if(str.empty()) return result;

        Permutation(str,result,0);

        // 此时得到的result中排列并不是字典顺序,可以单独再排下序
        sort(result.begin(),result.end());

        return result;
    }

    void Permutation(string str,vector<string> &result,int begin)
    {
        if(begin == str.size()-1) // 递归结束条件:索引已经指向str最后一个元素时
        {
            if(find(result.begin(),result.end(),str) == result.end())
            {
                // 如果result中不存在str,才添加;避免aa和aa重复添加的情况
                result.push_back(str);
            }
        }
        else
        {
            // 第一次循环i与begin相等,相当于第一个位置自身交换,关键在于之后的循环,
            // 之后i != begin,则会交换两个不同位置上的字符,直到begin==str.size()-1,进行输出;
            for(int i=begin;i<str.size();++i)
            {
                swap(str[i],str[begin]);
                Permutation(str,result,begin+1);
                swap(str[i],str[begin]); // 复位,用以恢复之前字符串顺序,达到第一位依次跟其他位交换的目的
            }
        }
    }

    void swap(char &fir,char &sec)
    {
        char temp = fir;
        fir = sec;
        sec = temp;
    }
};