LeetCode Hot 100 01 - 哈希
文章目录
- [LeetCode Hot 100 01 - 哈希](#LeetCode Hot 100 01 - 哈希)
开一个新坑。
小红书刷到有UU前面谈的都很好,结果最后手撕挂了,非常之可惜。遂以此为鉴,督促自己快快刷算法,同时也趁此机会继续不系统地学习C++和Python。此系列博客是个人向,纯为了督促自己干干干!
1. 两数之和
解法1:粗暴遍历
外循环 i = 0, numSize ,内循环 j = i+1, numSize 。时间复杂度 O(N^2) ,空间复杂度 O(1)。
C
c
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
for (int i = 0; i < numsSize; i++) {
for (int j = i + 1; j < numsSize; j++) {
if (nums[i] + nums[j] == target) {
int* indices = malloc(sizeof(int) * 2);
indices[0] = i;
indices[1] = j;
*returnSize = 2;
return indices;
}
}
}
*returnSize = 0;
return NULL;
}
注意C语言版要求是分配新的数组。
C++
C++
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int n = nums.size();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) {
return {i, j}; // vector类型
}
}
}
return {}; // 空vector
}
};
c++
std::vector<int>
表示一个元素类型为 int 的 vector 容器,可以存放多个整数,并且大小可以动态变化。
完整用法:
c++
#include <vector>
using namespace std;
vector<int> nums;
nums.push_back(10); // 添加元素
nums.push_back(20);
nums.push_back(30);
cout << nums.size(); // 当前元素个数
解法2:哈希表
核心理念是用哈希表记录"已经见过的数"。
从左到右遍历数组。对于每次遍历到的数,对其做:、
获取当前值
需要的另一个数 = target - 当前值
查哈希表是否有需要的另一个数
若有则输出
若没有则把当前值加入哈希表
这样,整体时间复杂度仅为 O(N) ,不过空间复杂度由原先的 O(1) 升为 O(N) ,属于空间换时间。
C++
c++
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> map; // <value, index>
for (int i = 0; i < nums.size(); ++i) {
int need = target - nums[i];
if (map.find(need) != map.end()) {
return {map[need], i};
}
map[nums[i]] = i;
}
return {};
}
};
LeetCode默认包含这两个头文件,自己写的时候要注意:
c++
#include <unordered_map>
#include <vector>
using namespace std;
C++中有语法如下:
c++
unordered_map<int, int>
含义为: value -> index 。这是一个无序表,内部通常为哈希表。同时,C++中也有有序表,内部通常为红黑树。
查找操作 :查找某个 value 在不在表中。 map.find(need) 的含义是"在 map 中找值为 need 的下标"。如果找到了,则返回 index ;如果没找到,则返回 map.end() ,即"没找到的标志"。通常来说:
c++
map.find(value) != map.end() // value 在 map 中存在
map.find(value) == map.end() // value 在 map 中不存在
读 index 操作 :读取某个元素的 index 。 map[value] 的返回值即为 index 。
插入操作 :把某个 value 和 index 插入到表中。 map[value] = index 即为把 value 插入到表中,并设置 index 。
C++优化
这里其实查了两次表,但是其实可以暂存查找结果:
c++
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> map; // value -> index
for (int i = 0; i < nums.size(); ++i) {
int need = target - nums[i];
auto it = map.find(need);
if (it != map.end()) {
return {it->second, i};
}
map[nums[i]] = i;
}
return {};
}
};
c++
auto it = map.find(need);
it 是一个迭代器,可以理解成"指向哈希表中某一组 key-value 的指针"。其中, it->first 是 value , it->second 是 index 。
C
需要手写哈希表实现,暂时略。
GPT题解暂存
c#define HASH_SIZE 20011 typedef struct Node { int key; // nums[i] int value; // index i struct Node* next; } Node; int hash(int key) { long long x = key; if (x < 0) x = -x; return x % HASH_SIZE; } Node* find(Node** table, int key) { int h = hash(key); Node* cur = table[h]; while (cur != NULL) { if (cur->key == key) { return cur; } cur = cur->next; } return NULL; } void insert(Node** table, int key, int value) { int h = hash(key); Node* node = (Node*)malloc(sizeof(Node)); node->key = key; node->value = value; node->next = table[h]; table[h] = node; } void freeTable(Node** table) { for (int i = 0; i < HASH_SIZE; i++) { Node* cur = table[i]; while (cur != NULL) { Node* temp = cur; cur = cur->next; free(temp); } } free(table); } /** * Note: The returned array must be malloced, assume caller calls free(). */ int* twoSum(int* nums, int numsSize, int target, int* returnSize) { Node** table = (Node**)calloc(HASH_SIZE, sizeof(Node*)); for (int i = 0; i < numsSize; i++) { int need = target - nums[i]; Node* found = find(table, need); if (found != NULL) { int* ans = (int*)malloc(sizeof(int) * 2); ans[0] = found->value; ans[1] = i; *returnSize = 2; freeTable(table); return ans; } insert(table, nums[i], i); } *returnSize = 0; freeTable(table); return NULL; }
