记录算法基础题思路:
step1
最长回文长度:https://leetcode-cn.com/problems/longest-palindrome/submissions/
给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。
int longestPalindrome(string s) {
/* 利用hash表统计全部字符数量,然后遍历每一个字符
如果为偶数length+=count,
如果为奇数length+=count-1, 并且置位中心数flag=1,
最终结果位length+flag*/
int c_map[256] = { 0 };
int center_flag = 0;
int length = 0;
for (int i = 0; i < s.length(); i++) {
c_map[s[i]]++;
}
for (int i = 0; i < 256; i++) {
if (c_map[i] % 2 == 0) {
length += c_map[i];
} else {
length += c_map[i] - 1;
center_flag = 1;
}
}
return length + center_flag;
}
词语模式匹配:https://leetcode-cn.com/problems/word-pattern/submissions/
给定一种规律 pattern 和一个字符串 str ,判断 str 是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。
bool wordPattern(string pattern, string str) {
/* 遍历字符串,建立一个str单词和pattern字符的hash表,
并且记录pattern中字符的使用状态,
如果出现一个表项建立过程对应字符已被使用,校验失败*/
bool c_used[256] = { 0 };
map <string, char> word_map;
string word;
int pos = 0;
str += ' ';//追加一个尾部空格,可以简化遍历条件
for (int i = 0; i < str.size(); i++) {
if (str[i] != ' ') {
word += str[i];
} else {
if (pos == pattern.length()) {
return false; //pattern长度不匹配
}
/* 获取到一个单词,单词表项没有就尝试建立表项 */
if(word_map.find(word) == word_map.end()) {
if (c_used[pattern[pos]] == true) {
return false; //对应字符位已经被占用,不能再映射
}
word_map[word] = pattern[pos];
c_used[pattern[pos]] = true;
} else {
if (word_map[word] != pattern[pos]) {
return false;//word已经构建hash表项,但映射的key值和当前不同
}
}
pos++;
word = "";
}
}
if (pos != pattern.length()) {
return false; //pattern长度不匹配
}
return true;
}
anagram分组:https://leetcode-cn.com/problems/group-anagrams/submissions/
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
/* 每个字符串单元排序结果作为key值,建立map字典,相同key追加到字典中 */
map<string, vector<string>> dict;
vector<vector<string>> res;
for (auto s : strs) {
string key = s;
sort(key.begin(),key.end());
dict[key].push_back(s);
}
for (auto it: dict) {
res.push_back(it.second);
}
return res;
}
无重复字符最长子串:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/submissions/
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度
示例:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
int lengthOfLongestSubstring(string s) {
/* 滑动窗口典型题
使用双指针start/end记录窗口边界,使用一个map记录当前滑动窗口内包含的字符,
滑动窗口右边界往后移动,比较每一个刚好要出现重复字符时,判断max_len是否要更新,
左边界移动,使窗口重新回到不存在重复字符的场景,然后继续右边界滑动。。。
*/
int start_pos = 0, end_pos = 0;
int max_len = 0;
char c_map[256] = { 0 };
int size = s.size();
while (end_pos < size && start_pos < size) {
/*滑块尾部往后移动 并在map中置位, 直到遇到某个字符已经存在与map中 */
while (end_pos < size && c_map[s[end_pos]] == 0) {
c_map[s[end_pos]] = 1;
end_pos++;
}
/* 更新当前长度 */
if (end_pos - start_pos > max_len) {
max_len = end_pos - start_pos;
}
/*移动滑块前start面,直到end_pos所在字符出块*/
while (start_pos < size && s[start_pos] != s[end_pos]) {
c_map[s[start_pos]] = 0;
start_pos++;
}
start_pos++;
end_pos++;
}
return max_len;
}
重复DNA序列:https://leetcode-cn.com/problems/repeated-dna-sequences/solution/
所有 DNA 都由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。
编写一个函数来查找 DNA 分子中所有出现超过一次的 10 个字母长的序列(子串)。
vector<string> findRepeatedDnaSequences(string s) {
/* 枚举每个10字符子串,插入map表中并累加计数,
最后遍历一次map */
map <string , int> word_map;
vector<string> res;
for (int i = 0; i < s.length(); i++) {
string word = s.substr(i, 10);
word_map[word]++;
}
map <string , int> :: iterator it;
for (it = word_map.begin(); it != word_map.end(); it++) {
if (it->second > 1) {
res.push_back(it->first);
}
}
return res;
}
最小覆盖子串:https://leetcode-cn.com/problems/minimum-window-substring/submissions/
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
public:
string minWindow(string s, string t) {
/* 滑动窗口 典型题
left right表示窗口边界,map_t表示t的字符映射计数,map_s表示窗口中字符映射计数
先right向后移动,直到s包含t,然后移动left直到s不包含t,刷新lengh_min, 记录res,
继续right向后移动直到s包含t。。。直到right走到末尾最后一次移动left更新res */
int map_s[128] = {0};
int map_t[128] = {0};
for (int i = 0; i < t.length(); i++) {
map_t[t[i]]++;
}
int left = 0;
int right = 0;
int min_length = 0;
string res;
for (right = 0;right < s.size(); right++) {
map_s[s[right]]++;
/* 移动right找到第一个包含t的窗口 */
while ((is_win_ok(map_s, map_t) == false) && right < s.size() - 1) {
right++;
map_s[s[right]]++;
}
if (is_win_ok(map_s, map_t) == false) {
return res; //始终无法找到一个包含点
}
/* 找到包含窗口开始移动left找当前right下最小窗口 */
while (is_win_ok(map_s, map_t) == true) {
map_s[s[left]]--;
left++;
}
/* 刷新min_length和res */
if (min_length == 0) {
min_length = right - left + 2;//注意left此时已经超过了满足win包含的位置
res = s.substr(left - 1, min_length);
} else {
if (min_length > right - left + 2) {
min_length = right - left + 2;
res = s.substr(left - 1, min_length);
}
}
}
return res;
}
private:
bool is_win_ok(int map_s[128], int map_t[128]) {
for (int i = 0; i < 128; i++) {
if (map_t[i] > map_s[i]) {
return false;
}
}
return true;
}