【前缀和:3. 无重复字符的最长子串】

题目链接:3. 无重复字符的最长子串

连续子数组问题,可以使用前缀和

而使用滑动窗口必须满足单调性!

方法1:前缀和+暴力枚举
  1. 统计前缀和
  2. 枚举前缀和数组的右端点,然后对于每个右端点,每次都枚举所有端点
java 复制代码
class Solution {
  public int subarraySum(int[] nums, int k) {
    int n = nums.length;
    int [] s = new int[n + 1];
    //统计前缀和
    for (int i = 0; i < n; i++){
      s[i+1] = s[i] + nums[i];
    }
    int ans = 0;
    for(int right = 1; right < n+1; right++){
      int left = 0;
      //暴力枚举
      while (left < right){
        if (s[right] - s[left] == k){
          ans++;
        }
        left++;
      }

    }
    return ans;
  }
}
方法2:前缀和+哈希表
  1. 我们统计完前缀和之后,我们要找的是s[j]-s[i]==k
  2. 可以把问题转换成s 中有多少对下标 (i,j) 满足 0≤i<j≤n 且 s[j]−s[i]=k
  3. 写成s[i]=s[j]-k,,这就是两数之和,利用哈希表"枚举右,维护左"
    • 枚举当前的前缀和 s[j],看看曾经有多少个前缀和等于 s[j]−k(配对)
    • 比如 s[j]=2,那么 s[i]=s[j]−k=2−1=1,我们要找的是 j左边有多少个 s[i]=1即可。这个操作可以使用哈希表
写法1:两次遍历
java 复制代码
class Solution {
  public int subarraySum(int[] nums, int k) {
    //统计前缀和
    int n = nums.length;
    int[] s = new int[n + 1];
    for (int i = 0; i < n; i++) {
      s[i + 1] = s[i] + nums[i];
    }

    //维护左,枚举右
    Map<Integer,Integer> cnt = new HashMap<>();
    int ans = 0;
    for(int x : s){
      ans += cnt.getOrDefault(x - k,0);
      cnt.merge(x,1,Integer::sum);
    }
    return ans;
  }
}
写法二:一次遍历
  • 我们可以一边计算前缀和,一边遍历前缀和。

  • 在遍历 nums 之前,我们需要先记录 s0=0,即空前缀的元素和等于 0。往 cnt 中添加 cnt0=1。

java 复制代码
class Solution {
  public int subarraySum(int[] nums, int k) {
    Map<Integer, Integer> cnt = new HashMap<>(nums.length + 1, 1); // 预分配空间
    cnt.put(0, 1); // s[0]=0 单独统计
    int s = 0;
    int ans = 0;
    for (int x : nums) {
      s += x;
      ans += cnt.getOrDefault(s - k, 0);
      cnt.merge(s, 1, Integer::sum); // cnt[s]++
    }
    return ans;
  }
}
写法三:一次遍历
  • 在同一轮循环中,先把 s *i* −1 加入哈希表,再根据 s *i* 更新答案。
  • 这样写无需初始化 cnt0=1。
java 复制代码
class Solution {
  public int subarraySum(int[] nums, int k) {
    Map<Integer, Integer> cnt = new HashMap<>(nums.length, 1); // 预分配空间
    int s = 0;
    int ans = 0;
    for (int x : nums) {
      cnt.merge(s, 1, Integer::sum); // cnt[s]++
      s += x;
      ans += cnt.getOrDefault(s - k, 0);
    }
    return ans;
  }
}

如果这篇文章对你有帮助,欢迎点赞、评论、关注、收藏。你们的支持是我前进的动力!

相关推荐
youtootech5 小时前
HarmonyOS《柚兔学伴》项目实战09-待办列表 UI——List+ForEach+滑动删除
数据结构·ui·华为·list·harmonyos
:-)6 小时前
算法-归并排序
java·开发语言·数据结构·算法·排序算法
Jerry10 小时前
LeetCode 101. 对称二叉树
算法
可编程芯片开发11 小时前
基于MPPT最大功率跟踪的离网光伏发电系统Simulink建模与仿真
算法
AI科技星12 小时前
线性算子不是空间映射函数,是全域双螺旋场之间拉伸、旋转、耦合、坍缩的跨空间标准化变换载体《全域数学vs传统数学:人类文明进阶200讲》第80讲
线性代数·算法·矩阵·数据挖掘·回归·乖乖数学·全域数学
米罗篮12 小时前
矩阵快速幂 (Exponentiation By Squaring Applied To Matrices)
c++·线性代数·算法·矩阵
dream_home840712 小时前
图像算法模型NPU适配与算法服务实战指南
人工智能·python·算法·npu 图像服务
大鱼>12 小时前
多宠物家庭智能管理平台:云端架构与多设备协同实战
python·算法·iot·宠物
To_OC13 小时前
LC 22 括号生成:刷完这道题,我终于搞懂回溯剪枝了
javascript·算法·leetcode
To_OC13 小时前
LC 39 组合总和:回溯入门必刷题,我踩过的两个坑都在这了
javascript·算法·leetcode