哈希表练习题
题目一:两个数组的交集
题目描述:
给定两个数组 nums1
和 nums2
,返回 它们的交集。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
sample1
Input | Output |
nums1 = [1,2,2,1], nums2 = [2,2] | [2] |
题解:
哈希表法,用两个哈希表来记录两个数组的情况,遍历数组1和2将他们的值作为hash的下标,全部标记成1。2.遍历两个哈希表,若有某个索引在两个数组中都被标记成1,就把这个元素添加到新动态内存分配的ret数组中。
代码:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
int hash1[1001] = { 0 };
int hash2[1001] = { 0 };
for (int i = 0; i < nums1Size; i++) {
hash1[nums1[i]] = 1;
}
for (int i = 0; i < nums2Size; i++) {
hash2[nums2[i]] = 1;
}
int k = 0;
int* ret = (int*)malloc(1000 * sizeof(int));
for (int i = 0; i < 1000; i++) {
if (hash1[i] == 1 && hash2[i] == 1) {
ret[k++] = i;
}
}
*returnSize = k;
return ret;
}
题目二:快乐数
题目描述:
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
sample1
Input | Output |
n = 19 | true |
题解:
出现sum为1时,就是快乐数,返回true.当sum不是1,且sum重复出现时,说明sum永远不可能等于1,进入无限循环,返回false,否则,hash继续++
代码:
int getsum(int n) {
int sum = 0;
while (n != 0) {
sum += (n % 10) * (n % 10);
n = n / 10;
}
return sum;
}
bool isHappy(int n) {
int sum = getsum(n);
int hash[1000] = { 0 };
while (sum != 1) {//没有出现1
if (hash[sum] == 1) {//出现重复
return false;
} else {
hash[sum]++;//没有重复sum
}
sum = getsum(sum);
}
return true;
}
题目三:两数之和
题目描述:
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
sample1
Input | Output |
nums = [2,7,11,15], target = 9 | [0,1] |
题解:
用哈希法来查询此时遍历的元素和给定target的差值,用map来存储遍历过的元素,因为既要判断是否存在还要记录下标位置,用key和val来存储元素及元素下标。遍历属于元素,在map中找差值,没有找到把当前元素存放到map中,继续遍历下一个元素,直到在map中找到元素差值,返回下标。
代码:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
struct hashTable {
int val;//存放下标
int key;//存放元素
UT_hash_handle hh;//表示哈希表项的句柄,方便地进行插入、删除和查找
};
struct hashTable* hashtable = NULL;
struct hashTable* find(int ikey) {//在map中查找元素
struct hashTable* s;
HASH_FIND_INT(hashtable, &ikey, s);//uhash库中特定的宏,查找元素
return s;
}
void insert(int ikey, int ival) {//在map中插入元素
struct hashTable* s = find(ikey);
if (s == NULL) {
struct hashTable* tmp = malloc(sizeof(struct hashTable));
tmp->key = ikey;
tmp->val = ival;
HASH_ADD_INT(hashtable, key, tmp);//uhash库中特定的宏,添加元素
} else {
s->val = ival;
}
}
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
hashtable = NULL;
for (int i = 0; i < numsSize; i++) {
struct hashTable* s = find(target - nums[i]);//遍历找差值
if (s != NULL) {
int* ret = malloc(sizeof(int) * 2);//动态内存分配
ret[0] = s->val;
ret[1] = i;
*returnSize = 2;
return ret;
}
insert(nums[i], i);
}
*returnSize = 0;//未找到符合条件的两个数
return NULL;
}
题目四:四数相加
题目描述:
给你四个整数数组 nums1
、nums2
、nums3
和 nums4
,数组长度都是 n
,请你计算有多少个元组 (i, j, k, l)
能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
sample1
Input | Output |
nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2] | 2 |
题解:
四数相加等于0,先计算两数之和,再在map中查找差值,差值为另外两组数字中的和,没有找到就保存到map中,找到就map中次数加1用 count记录出现和的次数,map是用来记录数字之和及出现次数。
代码:
struct hashTable {
int val;//次数
int key;//元素和
UT_hash_handle hh;//项柄
};
int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size) {
int count = 0;
struct hashTable* hashtable = NULL;
for (int i = 0; i < nums1Size; ++i) {//遍历数组1和2求两数之和
for (int j = 0; j < nums2Size; ++j) {
int ikey = nums1[i] + nums2[j];
struct hashTable* tmp;
HASH_FIND_INT(hashtable, &ikey, tmp);//宏,查找
if (tmp == NULL) {//没找到
struct hashTable* tmp = malloc(sizeof(struct hashTable));//分配内存
tmp->key = ikey, tmp->val = 1;//把和存放到map//存放次数
HASH_ADD_INT(hashtable, key, tmp);//宏,添加
}
else {//找到
tmp->val++;//次数加1
}
}
}
for (int i = 0; i < nums3Size; ++i) {//遍历数组3和4
for (int j = 0; j < nums4Size; ++j) {
int ikey = -nums3[i] - nums4[j];//记录差值
struct hashTable* tmp;
HASH_FIND_INT(hashtable, &ikey, tmp);//在map中找差值
if (tmp != NULL) {//找到了
count += tmp->val;//将map中记录次数的值赋给count;
}
}
}
return count;//返回count值
}