242.有效的字母异位词、 349. 两个数组的交集、202. 快乐数、1. 两数之和
242.有效的字母异位词
今天应该要学习的是hash表,考研时候也听说过,但是也没有实现过,甚至不了解任何的底层函数,今天先入入门吧,今天还要准备毕业论文的开题报告给导师看(本人还是大跨专业,今天好忙)
对于第一个题,我们首先要了解的基础知识:
字符m减去字符n会返回这两个字符之间的差值,
例如
char b='b';
char a='a';
cout<<b-a<<endl;
返回的结果就是1,也就是b和a差了1
for循环
我们常常使用的for循环都是诸如
for(int ii=0;ii<arr.size();ii++)
{
}
然而,还有另外一种可以利用for循环的方式
for(auto x:arr)
{
}
利用auto可以自动判别数组或者容器甚至是字符串内的成员类型,一个一个地遍历这个数组或者容器
知道这两点,我们就可以简便的完成这一道题目了
首先,我们可以制造一个数组arr,用于容纳字符串中各个字母的数量,例如a对应于数组arr【0】,b对应于arr【1】,以此类推
我们可以先遍历字符串s,求取对应位置的各个元素数量,然后再遍历令一个字符串t,使其对应位置的元素减减,这样如果两个字符串的各个字母的数量相同,那么我们起始定义的数组则会变成空数组,不然不是空数组。
代码
class Solution {
public:
bool isAnagram(string s, string t) {
int arr[26] = {0};
for(auto x:s)
{
arr[x-'a']++;
}
for(auto x:t)
{
arr[x-'a']--;
}
bool judge = true;
for(int ii=0;ii<26;ii++)
if(arr[ii]!=0)
judge = false;
return judge;
}
};
349. 两个数组的交集
这个题与上面的类似,因为输入的每个元素大小上限为999,所有我们可以创建一个大小为1000的数组,并初始化为0,分别遍历两个数组,遍历第一个数组,若数字对应位置的值是0,即遍历到该位置还没有出现这个数字,那么我们让它加一变成一;同理,我们遍历第二个数组,若数字对应位置的值是1,即只有第一个数组访问过的数字,我们让它加1变成2。
最后再访问这个数组,如果数组元素的值是2,我们将下标加入到容器中。
代码
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
int arr[1000]={0};
for(auto x:nums1)
if(arr[x]==0)
arr[x]++;
for(auto x:nums2)
if(arr[x]==1)
arr[x]++;
vector<int> tar;
for(int ii =0;ii<1000;ii++)
if(arr[ii]==2)
tar.push_back(ii);
return tar;
}
};
202. 快乐数
如题目,如果重复的计算可以得到一个1,那么这个数就是快乐数,但是如何判断这个数不是快乐数呢,难道要无限循环下去吗,显然不太现实,对此,我们认为如果要是出现重复的数字,那么它将这样循环下去,也就不再是快乐数。
对此,我们可以利用unordered_set
进行操作
unordered_set为无序容器,它的特性如下:
1.不再以键值对的形式存储数据,而是直接存储数据的值 ;
2.容器内部存储的各个元素的值都互不相等,且不能被修改;
3.不会对内部存储的数据进行排序
我们需要用到find()函数,即判断这个容器中是否存在这个数,如果存在,就返回迭代器,否则返回end()
insert()函数,将一个数插入到容器中
首先我们先写一个可以获得下一个数的函数
int get_num(int num)
{
int sum = 0;
while(num)
{
sum += (num%10)*(num%10);
num /= 10;
}
return sum;
}
这样就可以简化我们的代码;
代码
class Solution {
public:
int get_num(int num)
{
int sum = 0;
while(num)
{
sum += (num%10)*(num%10);
num /= 10;
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> set;
bool t = true;
while(t)
{
if(set.find(n)!=set.end())
t = false;
else
set.insert(n);
n = get_num(n);
if(n==1)
break;
}
return t;
}
};
1. 两数之和
暴力解法
如题所示,我们想到的最简单的莫过于暴力解法,我们只需要for循环两次即可完成,但是时间复杂度为O(n²)显然是一个不小的复杂度,但也确实可以解出该题目
代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> arr;
for(int ii=0;ii<nums.size();ii++)
{ if(arr.size()!=0)
break;
for (int jj = ii+1;jj<nums.size();jj++)
if(nums[ii]+nums[jj]==target)
{
arr.push_back(ii);
arr.push_back(jj);
break;
}
}
return arr;
}
};
利用map
map是用来记录访问过的数组及下标,可以更快的查找,unodered_map底层实现为hash table 所以可以更快的遍历
map的基本操作
map的创建–unordered_map<int,int> num;
map的插入–num.insert(pair<int,int>(nums[ii],ii));
map的查找–auto iter = num.find(target-nums[ii]);
若找到,则返回迭代器,否则返回num.end();
对于这道题,我们可以用map记录遍历过的元素及下标,当遍历一个新元素num[ii]的时候,若target-num[ii]存在于map之中,则返回map中的下标及num[ii]的ii,如果不存在,则将该元素及下表也放入map之中
代码
class Solution {
public:
vector twoSum(vector& nums, int target) {
unordered_map<int,int> num;
for(int ii=0;ii<nums.size();ii++)
{
auto iter = num.find(target-nums[ii]);
if(iter==num.end())
{
num.insert(pair<int,int>(nums[ii],ii));
}
else{
return {iter->second,ii};
}
}
return {};
}
};