1.两数之和(leetcode hot 100)

第一次:排序后索引号丢失,使用vector<pair<int,int>> vec保留索引好,解决这个问题;使用while(1)有死循环的风险,使用while (i<j) 来控制循环。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        int i=0,j=nums.size()-1;
        int sum;
        while(1){
            if(nums[j]>target)
                j--;
            else
                break;
        }
        while(1){
            sum=nums[i]+nums[j];
            if(sum>target){
                i++;
            }else if(sum<target){
                j--;
            }else{
                break;
            }
        }
        vector<int> ans;
        ans.push_back(i);
        ans.push_back(j);
        return ans;
    }
};

第二次:🔍 std::pair 默认排序规则:当你使用 std::sortpair<int, int> 排序时,默认按 first 元素升序排序,如果 first 相同,则比较 second

如果你需要自定义排序,比如按第二项排序,你可以写成:

sort(vec.begin(), vec.end(), [](const pair<int, int>& a, const pair<int, int>& b) {
    return a.second < b.second;
});

排序+双指针,但需要先保留索引,时间复杂度为O(n)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<pair<int,int>> vec;
        for(int i=0;i<nums.size();i++){
            vec.push_back({nums[i],i});
        }
        sort(vec.begin(), vec.end());
        
        int i=0,j=nums.size()-1;
​
        while(i<j){
            int sum=vec[i].first+vec[j].first;
            if(sum>target){
                j--;
            }else if(sum<target){
                i++;
            }else{
                return {vec[i].second,vec[j].second};
            }
        }
        
        return {};
    }
};

第三次:直接枚举,时间复杂度为O(n^2)

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};
                }
            }
        }
        return {};
    }
};

第四次:使用哈希表,每一次循环都可以在O(1)时间寻找到target-nums[i]

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> mp;
        for(int i=0;i<nums.size();i++){
            int complement=target-nums[i];
            if(mp.count(complement)){
                return {mp[complement],i};
            }
            mp[nums[i]]=i;
        }      
        return {}; 
    }
};

这道题目的目的是为了让我们认识到哈希表的强大性能,那么为什么哈希表可以在O(1)时间实现搜索?

  1. 直接定位: 哈希表通过哈希函数将键 key 映射成数组索引 index = hash(key),避免了线性搜索或树的逐层查找。

  2. 数组访问是 O(1): 查找变成“访问数组下标”,这是最基本、最快的数据访问操作,时间复杂度是 O(1)。

  3. 冲突少时效率极高: 好的哈希函数使不同的键分布均匀,减少冲突;即使冲突,也只在小范围内查找。

📌 举例:

如果你要查找 key = 42:

  • 哈希函数:hash(42) = 7

  • 你直接访问 table[7],一步就拿到值 —— 不需要排序、查找、比较!

一个简单的哈希表实现

/* 键值对 */
struct Pair {
  public:
    int key;
    string val;
    Pair(int key, string val) {
        this->key = key;
        this->val = val;
    }
};

/* 基于数组实现的哈希表 */
class ArrayHashMap {
  private:
    vector<Pair *> buckets;

  public:
    ArrayHashMap() {
        // 初始化数组,包含 100 个桶
        buckets = vector<Pair *>(100);
    }

    ~ArrayHashMap() {
        // 释放内存
        for (const auto &bucket : buckets) {
            delete bucket;
        }
        buckets.clear();
    }

    /* 哈希函数 */
    int hashFunc(int key) {
        int index = key % 100;
        return index;
    }

    /* 查询操作 */
    string get(int key) {
        int index = hashFunc(key);
        Pair *pair = buckets[index];
        if (pair == nullptr)
            return "";
        return pair->val;
    }

    /* 添加操作 */
    void put(int key, string val) {
        Pair *pair = new Pair(key, val);
        int index = hashFunc(key);
        buckets[index] = pair;
    }

    /* 删除操作 */
    void remove(int key) {
        int index = hashFunc(key);
        // 释放内存并置为 nullptr
        delete buckets[index];
        buckets[index] = nullptr;
    }

    /* 获取所有键值对 */
    vector<Pair *> pairSet() {
        vector<Pair *> pairSet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                pairSet.push_back(pair);
            }
        }
        return pairSet;
    }

    /* 获取所有键 */
    vector<int> keySet() {
        vector<int> keySet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                keySet.push_back(pair->key);
            }
        }
        return keySet;
    }

    /* 获取所有值 */
    vector<string> valueSet() {
        vector<string> valueSet;
        for (Pair *pair : buckets) {
            if (pair != nullptr) {
                valueSet.push_back(pair->val);
            }
        }
        return valueSet;
    }

    /* 打印哈希表 */
    void print() {
        for (Pair *kv : pairSet()) {
            cout << kv->key << " -> " << kv->val << endl;
        }
    }
};

但是上面哈希表的实现还有一些问题:

问题说明改进建议
❌ 没有处理冲突若两个 key 哈希到同一个位置,会发生覆盖使用链地址法(每个桶变为 vector 或链表)
❌ 无动态扩容当数据量大于桶数,会严重退化检测负载因子并 rehash
❌ 没有键比较仅靠 hash(key) 定位,没有比较实际键值插入、删除、查找时应比较 pair->key == key
❌ 手动内存管理麻烦使用原始指针,易出错unique_ptr 或智能指针管理内存

下面是一个支持冲突处理(链地址法)+ 自动扩容(rehash)+ 负载因子管理的 C++ 哈希表类 ArrayHashMap 重构版本,完全自主实现核心功能:

✅ 功能特性

特性实现方式
哈希冲突处理链地址法(vector of vector)
负载因子阈值默认 0.75
自动扩容/rehash容量翻倍后重哈希
键值查找支持同键覆盖
删除操作支持安全删除
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class ArrayHashMap {
private:
    struct Pair {
        int key;
        string val;
        Pair(int k, string v) : key(k), val(v) {}
    };

    vector<vector<Pair>> buckets; // 哈希桶(链地址法)
    int capacity;                 // 桶数量
    int size;                     // 当前元素数量
    const float loadFactorThreshold = 0.75;

    /* 哈希函数 */
    int hashFunc(int key) const {
        return key % capacity;
    }

    /* 自动扩容 */
    void rehash() {
        int oldCapacity = capacity;
        capacity *= 2;
        vector<vector<Pair>> newBuckets(capacity);

        for (const auto &bucket : buckets) {
            for (const Pair &pair : bucket) {
                int index = hashFunc(pair.key);
                newBuckets[index].emplace_back(pair.key, pair.val);
            }
        }
        buckets = move(newBuckets);
    }

public:
    ArrayHashMap(int initCap = 100) : capacity(initCap), size(0) {
        buckets = vector<vector<Pair>>(capacity);
    }

    /* 插入或更新 */
    void put(int key, const string &val) {
        int index = hashFunc(key);
        for (Pair &p : buckets[index]) {
            if (p.key == key) {
                p.val = val; // 若存在,更新
                return;
            }
        }
        buckets[index].emplace_back(key, val);
        size++;

        if ((float)size / capacity > loadFactorThreshold) {
            rehash();
        }
    }

    /* 查询 */
    string get(int key) const {
        int index = hashFunc(key);
        for (const Pair &p : buckets[index]) {
            if (p.key == key)
                return p.val;
        }
        return "";
    }

    /* 删除 */
    void remove(int key) {
        int index = hashFunc(key);
        auto &bucket = buckets[index];
        for (auto it = bucket.begin(); it != bucket.end(); ++it) {
            if (it->key == key) {
                bucket.erase(it);
                size--;
                return;
            }
        }
    }

    /* 所有键值对 */
    vector<Pair> pairSet() const {
        vector<Pair> result;
        for (const auto &bucket : buckets) {
            for (const Pair &p : bucket)
                result.push_back(p);
        }
        return result;
    }

    /* 打印 */
    void print() const {
        for (const auto &bucket : buckets) {
            for (const Pair &p : bucket) {
                cout << p.key << " -> " << p.val << endl;
            }
        }
    }
};

哈希表的学习,参考这里:第 6 章   哈希表 - Hello 算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值