原地哈希/LeetCode [41/442/448]

这种原地哈希算法适用于和正整数有关,且数字范围和数组长度有关的题目里,映射之后能利用映射关系(下标和值一一对应)来找到解。

1.题目链接:https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/

  • 由于不能使用额外空间,哈希表等其他数据结构就无法使用了。
  • 我们采取一种特殊的原地哈希f(nums[i]) = num[i] - 1,也就是将值为nums[i]的数字映射到nums[i]-1的下标位置,例:3映射到数组下标为2。
  • 算法过程:
  • 1.遍历数组,然后采取原地哈希,将现在位置上的数和映射过后下标(idx)上的数交换,循环直到nums[nums[i] - 1] != nums[i](也就是idx上的数和目前的数一样了)。
  • 2.最后再遍历一下这个调整过的数组,发现值和下标不对应的话,说明和这个下标对应的值没有出现过了。
class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        int n = nums.size();
        auto ans = vector<int>{};

        //f(nums[i]) = nums[i] - 1
        for(int i = 0; i < n; ++i){
            while(nums[nums[i] - 1] != nums[i]){
                int idx = nums[i] - 1;
                int t = nums[idx];
                nums[idx] = nums[i];
                nums[i] = t;
            }
        }

        for(int i = 0; i < n; ++i){
            if(nums[i] - 1 != i) ans.push_back(i + 1);
        }

        return ans;
    }
};

2.https://leetcode-cn.com/problems/first-missing-positive/

  • 思路和上题差不多也是采用原地哈希
  • 将小于n且大于0的值映射到相关位置上(index = nums[i] - 1,这样重新遍历的时候,第一个和下标不对应的就是第一个没出现过的最小的正整数。
  • 这里映射的时候要减1,不能2映射到下标2,不然的话下标0放什么数就不懂了。
class Solution {
public:
    int firstMissingPositive(vector<int> &nums) {
        int n = nums.size();
        for (int i = 0; i < n; i++) {
            while (nums[i] != i + 1) {
                if (nums[i] <= 0 || nums[i] > n || nums[i] == nums[nums[i] - 1])
                    break;
                // 将nums[i] 放置到对应位置上[1,2,3...]
                int idx = nums[i] - 1;
                nums[i] = nums[idx];
                nums[idx] = idx + 1;
            }
        }
        for (int i = 0; i < n; i++) {
            if (nums[i] != (i + 1)) {
                return (i + 1);
            }
        }
        return (n + 1);
    }
};

3.https://leetcode-cn.com/problems/find-all-duplicates-in-an-array/

  • 同样原地哈希
class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        int n = nums.size();
        auto ans = vector<int>{};

        for(int i = 0; i < n; ++i){
            while(nums[nums[i] - 1] != nums[i]){
                int idx = nums[i] - 1;

                int t = nums[idx];
                nums[idx] = nums[i];
                nums[i] = t; 
            }
        }
        
        for(int i = 0; i < n; ++i){
            if(i != nums[i] - 1) ans.push_back(nums[i]);
        }
        return ans;

        // unordered_set<int> hash_set;
        // for(auto num : nums){
        //     if(hash_set.count(num)) ans.push_back(num);
        //     else hash_set.insert(num);
        // }

        // return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值