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

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

相关推荐
1000世界小札1 小时前
《大话数据结构》第9章精读:归并排序与快速排序完整 C++ 实现
数据结构·c++·算法
2601_956121974 小时前
背包基础篇(01、完全、分组、多重、混合)
c++·算法·动态规划
兴通物联科技5 小时前
SMT PCB 微小 DataMatrix 码扫不动问题分析 兴通 XT8601B 600 万像素工业读码器落地实践
大数据·人工智能·单片机·嵌入式硬件·算法·计算机视觉
月华路8 小时前
G1 GC 对数组与大对象(Humongous)的处理
java·jvm·算法
我想走路带风8 小时前
LRU和最长前缀和(计算机网络算法)
计算机网络·算法
M78佐菲8 小时前
Linux学习笔记:进程
linux·笔记·学习·算法
徐小夕10 小时前
表格、文档、甘特、大屏、表单一站打通:pxcharts超级表格4.0正式上线!
前端·算法·github
Xin77010 小时前
LeetCode 23.合并 K 个升序链表(分治递归)
leetcode
TechLee10 小时前
跨语言加解密总对不上?这个纯 Go 神库让 AES/RSA 与 PHP、Java 100% 互通
java·后端·算法