当前位置: 首页 > news >正文

Hot100速刷计划day04(10-12)

Hot100速刷计划day04(10-12)

10 和为k的子数组

image-20241024104911314

时间复杂度:O(n)
class Solution {public int subarraySum(int[] nums, int k) {int []s = new int[nums.length+1];s[0] = 0;for (int i = 0; i < nums.length; i++) {s[i+1] = nums[i] + s[i];}int count = 0;HashMap<Integer,Integer> map = new HashMap<>(s.length);for (int sj : s) {count+=map.getOrDefault(sj-k,0);map.merge(sj,1,Integer::sum);}return count;}
}
妙处
  • 采用了前缀和思想,用n的时间做了原本n^2的事
  • 采用hashmap来再次缩短时间
  • 采用hashmap的api来简化代码

(ps:解法来自灵神)

代码解释:
Map<Integer, Integer> cnt = new HashMap<>(n + 1); // 设置容量可以快 2ms
  • 定义一个哈希表 cnt:用于存储不同的前缀和出现的次数。键是前缀和的值,值是该前缀和出现的次数。
  • new HashMap<>(n + 1)n 是数组的长度,n + 1 用来预分配哈希表的初始容量,这样可以减少哈希表扩容带来的性能损耗,从而提高效率(快大约 2 毫秒)。
for (int sj : s) {ans += cnt.getOrDefault(sj - k, 0);cnt.merge(sj, 1, Integer::sum); // cnt[sj]++
}
1. 遍历数组 s:
  • sj 是当前的前缀和。
2. 查找 sj - k 是否存在:
  • cnt.getOrDefault(sj - k, 0):这里通过前缀和的性质,如果当前的前缀和 sj 减去 k 得到的前缀和 sj - k 已经出现在 cnt 中,说明存在一个子数组的和为 k。因此,通过 cnt.getOrDefault(sj - k, 0) 获取 sj - k 出现的次数,并累加到 ans 上。
  • ans += cnt.getOrDefault(sj - k, 0):累加满足条件的子数组个数。
3. 更新哈希表
  • cnt.merge(sj, 1, Integer::sum):这是 HashMapmerge 方法,用于将当前的前缀和 sj 插入到哈希表中。
    • 如果 sj 已经存在,则将其值(出现次数)加 1。
    • 如果 sj 不存在,则插入 sj,并将其对应的值设为 1。
    • Integer::sum 是 Java 的方法引用,表示两个整数相加的操作。

关键思想:

  • 前缀和:通过记录数组中每一位的累积和(前缀和),可以将问题转化为在数组中寻找某个差值的过程。
  • 哈希表:使用哈希表来存储和查询前缀和,能够使查询 sj - k 是否存在的操作时间复杂度降为 O(1)。

具体逻辑:

  1. 我们遍历数组中的每个元素,累积计算当前的前缀和 sj
  2. 然后,我们使用哈希表快速查询前缀和 sj - k 是否已经存在(即是否存在一个子数组的和为 k)。
  3. 最后,我们将当前前缀和 sj 的出现次数记录到哈希表 cnt 中。

image-20241024104952088


11 滑动窗口的最大值

class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;int []ans = new int[n-k+1];//最终答案总的数量Deque<Integer>deque = new ArrayDeque<>();for (int i = 0; i < n; i++) {//入(保持单调性[单调递减])while (!deque.isEmpty()&&nums[deque.getLast()]<nums[i]){deque.removeLast();}deque.addLast(i);//出(i和deque里面的第一个元素的差距大于k个)if(i-deque.getFirst()>=k){deque.removeFirst();}//记录答案(保证这个索引是合法的(前面k个还尚未构成完整的队列))//也就是窗口没满if(i >= k-1){ans[i-k+1] = nums[deque.getFirst()];}}return ans;}
}

image-20241024110743080

这个是一个单调队列的模版,用于处理类似的问题

要点
  • 此处的单调队列是单调递减的
  • 要多熟悉基础api的用法(map,set,deque),java还是有很多很方便的api的

12 最小覆盖子串

image-20241024113850313

时间复杂度:O(n+m)
class Solution {public String minWindow(String s, String t) {//s是长串,t是模版串//特殊情况处理int [] cnt_father = new int[128];int [] cnt_son = new int[128];//左右边界指针int ansLeft = -1;int ansRigth = s.length();int left = 0;for (int i = 0; i < t.length(); i++) {cnt_son[t.charAt(i)]++;}for (int i = 0; i < s.length(); i++) {cnt_father[s.charAt(i)]++;while (isCovered(cnt_father,cnt_son)){if(ansRigth - ansLeft > i - left){ansLeft = left;ansRigth = i;}cnt_father[s.charAt(left)]--;left++;}}//这个鲁棒性的判定设计够我学一年啊return ansLeft < 0 ? "":s.substring(ansLeft,ansRigth+1);}public boolean isCovered(int [] father,int [] son){for (int i = 0; i < father.length; i++) {if(father[i] < son[i])return false;}return true;}
}
妙处
  • 将是否有重合转换为数组之间的关系
  • 将异常的检测用一个标志变量和一个三元运算符解决(主要是ansLeft的判断–>没有满足条件的情况就一直设置为-1)

(ps:解法来自灵神)


http://www.mrgr.cn/news/57557.html

相关文章:

  • 构建一个好用的设备管理APP
  • Navicat导入Excel数据时数据被截断问题分析与解决方案
  • C++大坑之——多继承(菱形继承)
  • 【C++篇】探索STL之美:熟悉使用String类
  • 7. 配置
  • 基于单片机的 OLED 显示终端设计分析与研究
  • 【网页布局技术】项目六 制作表格并使用CSS美化
  • 【Linux】进程信号(下)
  • CCRC-CDO首席数据官的主要工作内容
  • 全新原生鸿蒙HarmonyOS NEXT发布,书写国产操作系统新篇章!同时,触觉智能发布OpenHarmony5.0固件
  • (一)ArkTS语言——申明与类型
  • day7:软件包管理
  • 力扣247题详解:中心对称数 II 的多种解法与模拟面试
  • 自动粘贴神器,数据复制粘贴快速处理记事本
  • RK平台操作GPIO的两种方法
  • 爬虫中代理ip的选择和使用实战
  • HCIP--1
  • Java 网络下载文件输出字节流
  • 鸿蒙开发融云Demo消息列表
  • 顶层模块中定义一个数组,如何 通过端口将这个数组传递给所有需要它的子模块
  • Find My折叠车|苹果Find My技术与折叠车结合,智能防丢,全球定位
  • 2024年6月份北京深信服——蓝中护网面试经验分享
  • 博客搭建之路:hexo搜索引擎收录
  • 程序员35岁何必苟且,打造一人企业开启创业之路
  • 软考信息安全
  • c# grpc 保姆级教学搭建grpc框架 服务端、客户端