Hash哈希

当需要快速查询数据的记录时:

  1. 手动按某规则为数据建立索引,利用数组维护数据
  2. 若1中需要开大数组爆内存,利用官方库的Hash集合,可以将最好情况下的时间复杂度优化到O(1)避免T和M。

1. LC 2036 最大好子数组和

VP双周赛123T3。一开始卡住了。一直想在Hash表里存每种数字出现的索引,查询nums[i]±k的所有可能索引,前缀和相减得到子数组和维护最大值。最后不出意外的T了。既然要找之前的最小前缀和,为啥不在Hash表里直接维护每个数字对应的最小前缀和呢?改完A了。

import java.util.HashMap;

class Solution {
    public long maximumSubarraySum(int[] nums, int k) {
        HashMap<Integer, Long> m = new HashMap<>();

        int n = nums.length;
        long[] prefix = new long[n+1];

        long ans = Long.MIN_VALUE;
        long sum = 0;

        for (int i = 0; i < n; i++) {
            sum += nums[i];
            prefix[i+1] = sum;

            Long nk = m.get(nums[i] - k);
            Long pk = m.get(nums[i] + k);
            
            if(nk!=null){
                ans = Math.max(ans,sum-nk);
            }
            
            if(pk!=null){
                ans = Math.max(ans,sum-pk);
            }

            Long pre = m.get(nums[i]);
            if(pre==null){
                m.put(nums[i],prefix[i]);
            }else{
                m.put(nums[i],Math.min(prefix[i],pre));
            }
        }
        
        return ans==Long.MIN_VALUE?0:ans;
    }
}

注意子数组是闭区间,前缀和数组里加个哨兵即可。然后这道题实际上不需要前缀和数组,滚动一个前缀和就可以了,闭区间滞后一个元素即可。

import java.util.HashMap;

class Solution {
    public long maximumSubarraySum(int[] nums, int k) {
        HashMap<Integer, Long> m = new HashMap<>();

        int n = nums.length;

        long ans = Long.MIN_VALUE;
        long sum = 0;

        for (int num : nums) {

            Long nk = m.get(num - k);
            Long pk = m.get(num + k);

            if (nk != null) {
                ans = Math.max(ans, sum + num - nk);
            }

            if (pk != null) {
                ans = Math.max(ans, sum + num - pk);
            }

            Long pre = m.get(num);
            if (pre == null) {
                m.put(num, sum);
            } else {
                m.put(num, Math.min(sum, pre));
            }

            sum += num;
        }

        return ans==Long.MIN_VALUE?0:ans;
    }
}

2. LC 3164 优质数对的总数Ⅱ

  1. 先筛选nums1中能被k整除的数,把x//k加入到数组中
  2. 哈希表m再统计nums2各个数字出现的频率
  3. 对于通过筛选的nums1中出现的数v,枚举[1:sqrt(v)],查看是否是因子d
    1. 不是因子跳过
    2. 是因子
      1. 是平方根,加 m[d]
      2. 不是平方根,加 m[d] + m[v//d]
from typing import List
from collections import defaultdict
import math

class Solution:
    def numberOfPairs(self, nums1: List[int], nums2: List[int], k: int) -> int:
        arr = []

        for x in nums1:
            if x%k==0:
                arr.append(x//k)

        m = defaultdict(int)

        for x in nums2:
            m[x] += 1
        
        res = 0
        for x in arr:
            for i in range(1,int(math.sqrt(x))+1):
                if x%i == 0:
                    res += m[i] + (m[x//i] if i*i!=x else 0)
        
        return res

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值