【前缀和: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 之前,我们需要先记录 s[0]=0,即空前缀的元素和等于 0。往 cnt 中添加 cnt[0]=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] 更新答案。
  • 这样写无需初始化 cnt[0]=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;
  }
}

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

相关推荐
Black蜡笔小新1 小时前
自动化AI算法训练服务器DLTM深度学习推理工作站AI赋能质检助力制造业智能化转型
人工智能·算法·自动化
小雅痞2 小时前
[Java][Leetcode simple] 205. 同构字符串
java·算法·leetcode
智者知已应修善业2 小时前
【51单片机独立按键控制数码管自增自减】2023-10-5
c++·经验分享·笔记·算法·51单片机
2301_800895102 小时前
第十四届蓝桥杯国赛b组真题---备战国赛版h
算法·蓝桥杯·深度优先
生信之灵2 小时前
告别模板配准:LAMNr Flow如何用一次求逆破解多模态解剖对齐难题
人工智能·算法
SHARK_pssm2 小时前
【数据结构——复杂度】
c语言·数据结构·经验分享·笔记
焜昱错眩..2 小时前
力扣周赛难题 3906.统计网格路径中好整数的数目——自我拆解学习与分析(数位dp上下界的奇妙)
学习·算法·leetcode·动态规划
wangl_922 小时前
初探 C# 15 的 Union Types
java·开发语言·算法·c#·.net·.net core
Smile灬凉城6662 小时前
逻辑回归数据集
算法·机器学习·逻辑回归