开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!
Leetcode学习之哈希表与字符串 (3)
1、重复的DNA序列 LeetCode187.
题目来源:
L
e
e
t
C
o
d
e
187.
R
e
p
e
a
t
e
d
D
N
A
S
e
q
u
e
n
c
e
s
LeetCode \ 187. \ Repeated \ DNA \ Sequences
LeetCode 187. Repeated DNA Sequences
描述:将DNA序列看作是只包含[‘A’,‘C’,‘G’,‘T’]4个字符的字符串,给一个DNA字符串,找到所有长度为10的且出现超过1次的子串。
1.1 方法一:枚举+Map映射
分析:
测试代码:
#include <stdio.h>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) {
map<string, int> word_map; //<单词,单词数量>的映射
vector<string> result;
for (int i = 0; i < s.length(); i++) {
string word = s.substr(i, 10); //复制子字符串,要求从指定位置开始,并具有指定的长度。这是子串,子串是连续的。巧妙!
if (word_map.find(word) != word_map.end()) {
word_map[word] = word_map[word] + 1;
}
else{
word_map[word] = 1;
}
}
map<string, int> ::iterator it;
for (it = word_map.begin(); it != word_map.end(); it++) {
if (it->second > 1) {
result.push_back(it->first);
}
}
return result;
}
};
int main() {
string s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT";
Solution solve;
vector<string> result = solve.findRepeatedDnaSequences(s);
for (int i = 0; i < result.size(); i++) {
printf("%s\n", result[i].c_str());
}
system("pause");
return 0;
}
效果图:
1.2 方法二:编码
分析:
测试代码:
#include <stdio.h>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int g_hash_map[1048576] = { 0 }; //哈希太大了,需要全局数组
string change_int_to_DNA(int DNA){
static const char DNA_CHAR[] = { 'A','C','G','T' };
string str;
for (int i = 0; i < 10; i++) { //将一个长度为10的片段,从整数转为字符串
str = str + DNA_CHAR[DNA & 3];
DNA = DNA >> 2;
}
return str;
}
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) { //s.size() = 32
vector<string> result;\
if (s.length() < 10) {
return result;
}
for (int i = 0; i < 1048576; i++) { //每次调用时需要更新全局数组
g_hash_map[i] = 0;
}
int char_map[128] = { 0 };
char_map['A'] = 0;
char_map['C'] = 1; //设置字符到整数的转换数组
char_map['G'] = 2;
char_map['T'] = 3;
int key = 0; //将DNA字符串的前10个字符
for (int i = 9; i >= 0; i--) {
key = (key << 2) + char_map[s[i]];
}
g_hash_map[key] = 1;
for (int i = 10; i < s.length(); i++) {
key = key >> 2;
key = key | (char_map[s[i]] << 18);
g_hash_map[key]++;
}
for (int i = 0; i < 1048576; i++) {
if (g_hash_map[i] > 1) {
result.push_back(change_int_to_DNA(i));
}
} //将出现次数大于2的片段push进入结果
return result;
}
};
int main() {
string s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT";
Solution solve;
vector<string> result = solve.findRepeatedDnaSequences(s);
for (int i = 0; i < result.size(); i++) {
printf("%s\n", result[i].c_str());
}
system("pause");
return 0;
}
效果图:
2、最小窗口子串 LeetCode 76.
题目来源:
M
i
n
i
m
u
m
W
i
n
d
o
w
S
u
b
s
t
r
i
n
g
Minimum \ Window \ Substring
Minimum Window Substring
描述:已知字符串S与字符串T,求在S中的最小窗口(区间),使得这个区间中包含了字符串T中的所有字符。
分析:
测试代码:
#include <stdio.h>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
private:
//map_s[],map_t[]记录字符串里面各字符的个数,vector<int> 记录字符串中有哪些字符
//这两个数组是字符哈希数组 map_s代表当前处理的窗口区间的字符数量;map_t代表子串T的字符数量
bool is_window_ok(int map_s[], int map_t[], vector<int> &vec_t) {
for (int i = 0; i < vec_t.size(); i++) { //利用vec_t遍历t中出现的字符
if (map_s[vec_t[i]] < map_t[vec_t[i]]) {
return false; //如果s出现该字符的数量小于t中出现该字符的数量
}
}
return true;
}
public:
//i窗口尾指针
//begin窗口头指针
string minWindow(string s, string t) {
const int MAX_ARRAY_LEN = 128; //char 0-127.利用数组下标记录字符个数
int map_t[MAX_ARRAY_LEN] = { 0 }; //记录t字符串的各字符个数
int map_s[MAX_ARRAY_LEN] = { 0 }; //记录s字符串的各字符个数
vector<int> vec_t; //记录t字符串中有哪些字符、
for (int i = 0; i < t.length(); i++) {
map_t[t[i]]++; //遍历t,记录t字符串字符个数
}
for (int i = 0; i < MAX_ARRAY_LEN; i++) {
if (map_t[i] > 0) {
vec_t.push_back(i);
} // 遍历,将字符串t中出现的字符存储到vec_t中
}
int window_begin = 0; //最小窗口起始指针
string result; //最小窗口对应的字符串
for (int i = 0; i < s.length(); i++) { //i代表了窗口的尾指针
map_s[s[i]]++; //将尾指针指向的字符添加搭配表示窗口的map中
while (window_begin < i){ //窗口的头指针不能超过尾指针
char begin_ch = s[window_begin];
if (map_t[begin_ch] == 0) { //如果当前头指针指向的字符没有在字符串t中出现
window_begin++; //窗口头指针前移
} //头指针指向的字符出现在T中,窗口内有超过该字符个数的字符
else if (map_s[begin_ch] > map_t[begin_ch]) {
map_s[begin_ch]--; //头指针前移,它指向的字符减少1
window_begin++; //窗口头指针前移
}
else{
break; //除了1,2两个条件,其他情况都跳出循环
}
} //检查此时的窗口是否包含字符串t
if (is_window_ok(map_s, map_t, vec_t)) {
int new_window_len = i - window_begin + 1; //计算新字符串长度
if (result == "" || result.length() > new_window_len) {
result = s.substr(window_begin, new_window_len);
} //替换窗口所对应的字符串 结果字符串为空或者当前窗口字符串更小的时候更新结果
}
}
return result;
}
};
int main() {
Solution solve;
string result = solve.minWindow("ADOBECODEBANC", "ABC");
printf("%s\n", result.c_str());
result = solve.minWindow("MADOBCCABEC", "ABCC");
printf("%s\n", result.c_str());
result = solve.minWindow("aa", "aa");
printf("%s\n", result.c_str());
system("pause");
return 0;
}
效果图: