代码随想录算法训练营第6天| 242.有效的字母异位词 | 349. 两个数组的交集 | 202. 快乐数 | 1. 两数之和
哈希表理论基础
建议:大家要了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map。
什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。 这句话很重要,大家在做哈希表题目都要思考这句话。
文章讲解:https://programmercarl.com/%E5%93%88%E5%B8%8C%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
242.有效的字母异位词
建议: 这道题目,大家可以感受到 数组 用来做哈希表 给我们带来的遍历之处。
题目链接/文章讲解/视频讲解:
https://programmercarl.com/0242.%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D.html
C一刷:
bool isAnagram(char* s, char* t) {
int b[26]={0};//哈希算法---数组
int i;
for(i=0;i<strlen(s);i++)
b[s[i]-'a']++;//当s里面的元素放26字母数组中标记
for(i=0;i<strlen(t);i++)
b[t[i]-'a']--;//同上,如有不同26字母数组则会出现正负数
for(i=0;i<26;i++)
{
if(b[i]!=0)
return false;
}
return true;
}
C++2刷:
class Solution {
public:
bool isAnagram(string s, string t) {
int record[26]={0};
for(int i=0;i<s.size();i++)
record[s[i]-'a']++;
for(int i=0;i<t.size();i++)
record[t[i]-'a']--;
for(int i=0;i<26;i++)
if(record[i]!=0) return false;
return true;
}
};
349. 两个数组的交集
建议:本题就开始考虑 什么时候用set 什么时候用数组,本题其实是使用set的好题,但是后来力扣改了题目描述和 测试用例,添加了 0 <= nums1[i], nums2[i] <= 1000 条件,所以使用数组也可以了,不过建议大家忽略这个条件。 尝试去使用set。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0349.%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86.html
C一刷:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
int hash[10005]={0};
int lesssize=nums1Size<nums2Size?nums1Size:nums2Size;
int *result=(int *)calloc(lesssize,sizeof(int));
/*
C 库函数 void *calloc(size_t nitems, size_t size) 分配所需的内存空间,
并返回一个指向它的指针。malloc 和 calloc 之间的不同点是,malloc 不会设置内存
为零,而 calloc 会设置分配的内存为零。
注意:calloc() 函数将分配的内存全部初始化为零。
如果不需要初始化,可以使用 malloc() 函数代替。
另外,使用 calloc() 函数时需要注意,如果分配的内存块过大,
可能会导致内存不足的问题。
声明
下面是 calloc() 函数的声明。
void *calloc(size_t nitems, size_t size)
参数
nitems -- 要被分配的元素个数。
size -- 元素的大小。
返回值
该函数返回一个指针,指向已分配的内存。
如果请求失败,则返回 NULL。
*/
int resultindex=0;
int i;
for(i=0;i<nums1Size;i++)
hash[nums1[i]]=1;//把哈希数组中nums1里面的出现的元素全部标记
for(i=0;i<nums2Size;i++)
{
if(hash[nums2[i]]==1)//找2里有没有标记的元素
result[resultindex++]=nums2[i];//找到就给result数组
hash[nums2[i]]=0;//清零以防重复。
}
*returnSize=resultindex;//返回result数组长度
return result;
}
C++2刷:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> res_set;
unordered_set<int> nums_set(nums1.begin(),nums1.end());
for(int num:nums2)
{
if(nums_set.find(num)!=nums_set.end())//看是否有相等的num,找到并放入res_set内。
res_set.insert(num);
}
return vector<int>(res_set.begin(),res_set.end());
}
};
202. 快乐数
建议:这道题目也是set的应用,其实和上一题差不多,就是 套在快乐数一个壳子
题目链接/文章讲解:https://programmercarl.com/0202.%E5%BF%AB%E4%B9%90%E6%95%B0.html
C一刷:
int get_sum(int n) {
int sum = 0;
div_t n_div = { .quot = n };
while (n_div.quot != 0) {
n_div = div(n_div.quot, 10);
sum += n_div.rem * n_div.rem;
}
return sum;
}
/*
// (版本1)使用数组
bool isHappy(int n) {
// sum = a1^2 + a2^2 + ... ak^2
// first round:
// 1 <= k <= 10
// 1 <= sum <= 1 + 81 * 9 = 730
// second round:
// 1 <= k <= 3
// 1 <= sum <= 36 + 81 * 2 = 198
// third round:
// 1 <= sum <= 81 * 2 = 162
// fourth round:
// 1 <= sum <= 81 * 2 = 162
uint8_t visited[163] = { 0 };
int sum = get_sum(get_sum(n));
int next_n = sum;
while (next_n != 1) {
sum = get_sum(next_n);
if (visited[sum]) return false;
visited[sum] = 1;
next_n = sum;
};
return true;
}
*/
bool isHappy(int n) {
int slow = n;
int fast = n;
do {
slow = get_sum(slow);
fast = get_sum(get_sum(fast));
} while (slow != fast);
return (slow == 1);
}
/*int asum(int n) {
int sum = 0;
div_t n_div = { .quot = n };
while (n_div.quot != 0) {
n_div = div(n_div.quot, 10);
sum += n_div.rem * n_div.rem;
}
return sum;
}
bool isHappy(int n) {
//使用快慢表,比较简便
int slow=n;
int fast=n;
do
{
slow=asum(n);
fast=asum(asum(n));
}while(slow!=fast);
return (slow==1);//用了指针环的方法,很精妙,但是此方法容易超出代码时间限制
}*/
C++2刷:
class Solution {
public:
int getsum(int n)
{
int sum=0;
while(n)
{
sum+=(n%10)*(n%10);
n=n/10;
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> setsum;
while(1)
{
int a=getsum(n);
if(a==1)
return true;
if(setsum.find(a)!=setsum.end())
{
return false;
}
else
setsum.insert(a);
n=a;
}
}
};
1. 两数之和
建议:本题虽然是 力扣第一题,但是还是挺难的,也是 代码随想录中 数组,set之后,使用map解决哈希问题的第一题。
建议大家先看视频讲解,然后尝试自己写代码,在看文章讲解,加深印象。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0001.%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C.html
C一刷:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
typedef struct HashTable
{
int key;//数值作为key
int value;//数的下标作为value
UT_hash_handle hh;//必敲公式代码
}map;
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
map *hash=NULL;//创建哈希指针
int *res=(int*)malloc(sizeof(int)*2);
*returnSize=2;
for(int i=0;i<numsSize;i++)
{
map *ret=NULL;//接收查找后的返回值
int key=target-nums[i];
HASH_FIND_INT(hash,&key,ret); /*在哈希表中查找target - nums[i]*/
//如果没有查找到,则将nums[i]作为key加入哈希表中
if(ret==NULL)
{
map *num=(map*)malloc(sizeof(map));
num->key=nums[i];
num->value=i;
HASH_ADD_INT(hash,key,num);
//如果找到,则找到这两个数
}
else
{
res[0]=ret->value;
res[1]=i;//把找到两数的下标放到res[]中最后输出
}
}
return res;
//这上面讲的不错https://blog.csdn.net/Dusong_/article/details/128757067
}
C++2刷:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> map;
for(int i=0;i<nums.size();i++)// 遍历当前元素,并在map中寻找是否有匹配的key
{
auto iter=map.find(target-nums[i]);
if(iter!=map.end())
{
return {iter->second, i};
}
map.insert(pair<int,int>(nums[i],i));// 如果没找到匹配对,就把访问过的元素和下标加入到map中
}
return {};
}
};