算法2
查找问题
查找有无
-元素”a”是否存在?set 集合
查找对应关系(键值对应)
-元素”a”出现了几次?map 字典
set和map
通常语言的标准库都内置set和map
-容器类
-屏蔽实现细节
-了解语言中标准库常见容器类的使用
常见操作
-insert
-find
-erase
-change(map)
例题349:
给定两个数组nums,求两个数组的公共元素
-如nums1=[1,2,2,1],nums=[2,2]
-结果为[2]
-结果中每个元素只能出现一次
-出现的顺序可以是任意的
#include<iostream>
#include<vector>
#include<set>
using namespace std;
class Solution{
public:
vector<int>intersection(vector<int>&nums1,vector<int>&nums2){
for(int i =0;i<nums1.size();i++)
record.insert(nums[i])
set<int>resultSet
for(int i =0;i<nums2.size();i++)
if(record.find(nums2[i]) != record.end())
//find查找元素,如果查找到record.end()为止发现元素,则存在。
//如果=record.end()说明没有找到。说明nums2[i]存在
resultSet.insert(nums2[i])
vector<int>resultVector;
for(set<int>::iterator iter = resultSet.begin();iter!=resultSet.end();iter++)
resultVector.push_back(* iter);
return resultVector;
}
};
int main(){
return 0;
}
可以使用容器类的构造方法
#include<iostream>
#include<vector>
#include<set>
using namespace std;
class Solution{
public:
vector<int>intersection(vector<int>&nums1,vector<int>&nums2){
set<int> record(nums1.begin(),nums1.end()); //简化
set<int>resultSet;
for(int i =0;i<nums2.size();i++)
if(record.find(nums2[i]) != record.end())
//find查找元素,如果查找到record.end()为止发现元素,则存在。
//如果=record.end()说明没有找到。说明nums2[i]存在
resultSet.insert(nums2[i])
return vector<int>(resultSet.begin(),resultSet.end());//简化
}
};
int main(){
return 0;
}
例题350:
给定两个数组nums,求两个数组的交集
如nums1=[1,2,2,1],nums2=[2,2]
结果为[2,2]
出现的顺序可以是任意的
class Solution{
public:
vector<int>intersection(vector<int>&nums1,vector<int>&nums2){
map<int,int>record;
for(int i =0;i<nums1.size();i++)
record[nums1[i]]++; //记录频次
vector<int>resultVector;
for(int i =0;i<nums2.size();i++)
if(record[nums2[i]]>0){
resultVector.push_back(nums2[i]);
//nums2[i]);//如果发现在nums2中某以元素的频次也大于0,则记录下来
record[nums2[i]--];
}
return resultVector;
}
};
C++中map的默认值为0
换种写法风格
class Solution{
public:
vector<int>intersection(vector<int>&nums1,vector<int>&nums2){
map<int,int>record;
for(int i =0;i<nums1.size();i++)
if(record.find(nums1[i])== record.end())
record.insert(make_pair(nums1[i],1));//初始键值为1
record[nums1[i]]++; //如果存在某一元素则记录频次
vector<int>resultVector;
for(int i =0;i<nums2.size();i++)
if(record.find(nums2[i])!=record.end()&&record[nums2[i]]>0){
resultVector.push_back(nums2[i]);
//nums2[i]);//如果发现在nums2中某以元素的频次也大于0,则记录下来
record[nums2[i]--];
if(record[nums2[i]]==0)
record.erase(nums2[i]);//每求一次交集将这个元素抹去
}
return resultVector;
}
};
对于两个问题,如果数组有序?
set和map有不同的底层实现
哈希表
哈希表的缺点是失去了数据的顺序性
map和set的底层实现为平衡二叉树,时间复杂度为O(nlogn)
unordered_map 和 unordered_set 的底层实现为哈希表
数据的顺序性
-数据集中的最大值和最小值
-某个元素的前驱和后置
-某个元素的floor和ceil
-某个元素的排位rank
-选择某个排位的元素select
#include<iostream>
#include<vector>
#include<unordered_set>
using namespace std;
//时间复杂度O(n)
//空间复杂度O(n)
class Solution{
public:
vector<int>intersection(vector<int>&nums1,vector<int>&nums2){
unordered_set<int> record(nums1.begin(),nums1.end()); //简化
unordered_set<int>resultSet;
for(int i =0;i<nums2.size();i++)
if(record.find(nums2[i]) != record.end())
//find查找元素,如果查找到record.end()为止发现元素,则存在。
//如果=record.end()说明没有找到。说明nums2[i]存在
resultSet.insert(nums2[i])
return vector<int>(resultSet.begin(),resultSet.end());//简化
}
};
int main(){
return 0;
}
unordered_map 哈希表底层实现为O(1)
//时间复杂度O(n)
//空间复杂度O(n)
class Solution{
public:
vector<int>intersection(vector<int>&nums1,vector<int>&nums2){
unordered_map<int,int>record;
for(int i =0;i<nums1.size();i++)
record[nums1[i]]++; //记录频次
vector<int>resultVector;
for(int i =0;i<nums2.size();i++)
if(record[nums2[i]]>0){
resultVector.push_back(nums2[i]);
//nums2[i]);//如果发现在nums2中某以元素的频次也大于0,则记录下来
record[nums2[i]--];
}
return resultVector;
}
};
例题:242 Valid Anagram
判断字符串t是否是字符串s变换字符顺序后得到的结果
如s = “anagram” ,t = “nagaram”,则返回true
如s = “rat”, t = “car” ,则返回false
例题: 202 Happy number
判断一个数是否为happy number。happy number是指,一个数,将其替换为其各位数字的平方和,重复这个过程,如果最终能得到1,这是happy number,如果这个过程陷入了一个不包含1的循环,则不是happy number
如:数字19:
1^2+9^2 = 82
8^2+2^2 = 68
6^2+8^2 = 100
1^2+0^2+0^2 = 1 Happy number!
例题: 290 word pattern
给定一个模式和一个字符串,判断字符串是否符合模式
例题: 205 Isomorphic Strings
判断两个字符串是否同构?
例题: 251
给定一个字符串,按照字母出现频率的倒序重组整个字符串
一个使用查找表的经典问题
例题: 1 Two Sum
给定一个整型数组nums。返回这个数组两个数字的索引值i和j
使得nums[i]+nums[j] = 一个给定的target
-索引从0开始
-没有解怎么办
-有多个解怎么办 ,保证有唯一解
class Solution{
public:
vector<int>twoSum(vector<int>&nums,int target){
unordered_map<int,int>record;
for(int i = 0;i<num.size();i++)
record[nums[i]] = i;
int complement = target - nums[i];
if(record.find(complement)!= record.end()){
int res[2] = {i,record[complement]};
return vector<int>(res,res+2);
}
record[nums[i]] = i;
}
throw invalid_arguement("the input has no solution")
}
例题: 219
给出一个整型数组nums和一个整数k,是否存在索引i和j,使得nums[i] == nums[j]
且i,j之间的差不超过k
这个问题也是使用滑动窗口查找表
//时间复杂度O(n)
//空间复杂度O(k)
class Solution{
public:
bool containsNearbyDuplicate(vector<int>& nums,int k){
unordered_set<int>record;
for (int i = 0;i<nums.size();i++){
if(record.find(nums[i])!=record.end()) //如果新的元素在原窗口中找得到,返回true
return true;
record.insert(nums[i]);
//如果新的元素原窗口中不存在,则添加该元素
if(record.size()==k+1) //保持record最多k个元素
record.erase(nums[i-k]);
}
return false;
}
};
例题:217 Contains Duplicate
例题:220
给出一个整型数组nums和一个整数k,是否存在索引i和j,使得nums[i]和nums[j]之间的差别不超过给定整数t,且i,j之间的差不超过整数k
//时间复杂度O(n)
//空间复杂度O(k)
#include<vector>
#include<set>
using namespace std;
class Solution{
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums,int k,int t){
set<int>record;
for (int i = 0;i<nums.size();i++){
if(record.lower_bound(nums[i]-t)!=record.end() && *record.lower_bound(nums[i]-t)<=nums[i]+t)
//确保寻找的元素在[v-t,v+t]的范围内
return true;
record.insert(nums[i]);
//如果新的元素原窗口中不存在,则添加该元素
if(record.size()==k+1) //保持record最多k个元素
record.erase(nums[i-k]);
}
return false;
}
};