题目一:. - 力扣(LeetCode)
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
//超时,O(n2)
// for(int i=0;i<nums.size();i++)
// {
// for(int j=i+1;j<nums.size();j++)
// {
// if(nums[i]==nums[j]&&j-i<=k)
// return true;
// }
// }
// return false;
// for(int length=2;length<=k+1;length++)
// {
// int temp=nums.size()-length;
// for(int i=0;i<=temp;i++)
// {
// if(nums[i]==nums[i+length-1])return true;
// }
// }
unordered_set<int>s;
for(int i=0;i<nums.size();i++)
{
if(i>k)s.erase(nums[i-k-1]);
if(s.find(nums[i])!=s.end())return true;
s.insert(nums[i]);
}
return false;
}
};
前两个都能过,但是第二个显然效率低得多。第二个严格意义上还是暴力,不算滑动窗口。
维护一个哈希表,哈希表最大长度为k+1,如果超过该长度则移除最前面的元素。不断判断直到哈希表内出现重复元素,即满足条件。
题目二:哈希表+滑动窗口+位运算
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) {
// vector<string>res;
// if (s.length() <= 10)return res;
// unordered_multiset<string>set;
// int left = 0, right = 10;
// string str(s.begin(), s.begin() + 10);
// set.insert(str);
// while (right < s.length())
// {
// str.erase(str.begin());
// str += s[right];
// if (set.count(str) == 1)
// {
// set.insert(str);
// res.push_back(str);
// }
// else if(set.count(str)==0)
// set.insert(str);
// right++;
// }
// return res;
unordered_map<char, int>bin = { {'A',0},{'C',1},{'G',2},{'T',3} };
vector<string>res;
if (s.length() <= 10)return res;
int x = 0;
for (int i = 0; i < 10; i++)
{
x = (x << 2) | bin[s[i]];
}
unordered_map<int, int>map;
map[x] = 1;
for (int i = 10; i < s.length(); i++)
{
x = ((x << 2) | bin[s[i]]) & ((1 << 20) - 1);
if (map[x] == 1)
{
res.push_back(s.substr(i - 10 + 1, 10));
map[x] = 2;
}
else if(map[x]==0)map[x] = 1;
}
return res;
}
};
第一种方式(注释代码):即维护一个长度为10的set,当发现集合中元素已经出现过时将该元素加入集合,使用mulitiseset,可以加入重复元素,仅当个数为1时才加入结果集中,防止重复。
第二种方式使用了位运算,因为只有4种状态,可以使用二进制00,01,10,11来表示。10个便是20位,使用一个int,32位完全足够,且只需要使用低20位。存哈希表时不再存字符串而存储其对应的int值,保证能一一映射。滑动窗口时,当前数x左移两位,或运算上新来的数字,并且与运算(1<<20)-1,即低20位不变高12位清零。
位运算,很巧妙。