【前缀和: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;
  }
}

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

相关推荐
明志数科17 小时前
4D时序标注技术详解:让机器人理解连续动作的数据基础
java·算法·机器人
KaMeidebaby17 小时前
卡梅德生物技术快报|原核表达系统工艺优化:包涵体重折叠 + 分子筛纯化实现功能 RBD 高效制备,附全参数配置
前端·人工智能·算法·数据挖掘·数据分析
无限码力18 小时前
携程0510笔试真题【单数组交换】
算法·携程笔试·携程笔试真题·携程0510笔试真题
Love_云宝儿18 小时前
WKT数据示例并与GeoJSON数据对比
数据结构·gis
BlockWay18 小时前
WEEX Labs 周度观察:微软-OpenAI 合作调整与AI 多云趋势
大数据·人工智能·算法·安全·microsoft
风筝在晴天搁浅19 小时前
快手 CodeTop LeetCode 224.基本计算器
数据结构·算法·leetcode
Smoothcloud润云19 小时前
5大功能精修,重构AI算力使用体验!
java·人工智能·windows·算法·重构·编辑器·sublime text
计算机安禾19 小时前
【算法分析与设计】第41篇:确定性与非确定性多项式时间:P与NP的形式化
算法
牢姐与蒯19 小时前
c++数据结构之c++11(一)
数据结构·c++
iiiiyu19 小时前
IO流(二)
java·开发语言·数据结构·编程语言