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>

表示一个元素类型为 intvector 容器,可以存放多个整数,并且大小可以动态变化。

完整用法:

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 操作 :读取某个元素的 indexmap[value] 的返回值即为 index

插入操作 :把某个 valueindex 插入到表中。 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->firstvalueit->secondindex

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;
}
相关推荐
浅念-4 小时前
LeetCode回溯算法从入门到精通完整解析
开发语言·数据结构·c++·算法·leetcode·dfs·深度优先遍历
雪度娃娃4 小时前
行为型设计模式——迭代器模式
c++·设计模式·迭代器模式
青云计划4 小时前
数据库的ID的另一种选择-雪花算法
数据库·算法
代码地平线4 小时前
⭐️C++入门基础精讲(一):从发展历史到第一个程序
大数据·c++·后端·深度学习
夏日听雨眠4 小时前
linux(线程,线程同步 方法 互斥锁 信号量 条件变量 )
linux·运维·算法
神经网络机器学习智能算法画图绘图4 小时前
基于改进的支持向量机多分类预测研究
算法·支持向量机·分类
阿Y加油吧4 小时前
两道经典算法题复盘:最长有效括号 & 不同路径
算法
晚风叙码4 小时前
一文吃透二叉树:前中后序遍历+节点数+树高+叶子节点(含完整源码)
数据结构·算法
迦南的迦 亚索的索4 小时前
机器学习_05_k-means算法
算法·机器学习·kmeans