陆续更新字符串题目
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; } };