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

剑指数组相关

LCR 006. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

  • 关键词: 升序排列 两数之和等于目标数

  • 两数之和没有要求是连续的两个数字,所以不用滑动窗口/快慢指针.

  • 但总得从数组的某侧去开始计算和,数组是升序数组,如l从左侧出发,target-numbers[l]如果大于最右侧数据,说明此时numbers[l]太小,l++;同理从右边出发.

  • 所以维护一个左右指针,直至二者重合,否则期间会存在一个数据之和==target

class Solution {public int[] twoSum(int[] numbers, int target) {int l=0,r=numbers.length-1;while(l<r){int rem = target-numbers[r];while(numbers[l]<rem) l++;if(numbers[l] == rem){return new int[]{l,r};}r--;}return new int[]{-1,-1};}
}

LCR 007. 三数之和 - 力扣(LeetCode)

  • 三数之和为0 不重复

  • 首先想可能有哪些解法: 滑动窗口 快慢指针 左右指针

  • 由于不要求连续子数组,所以滑动窗口/快慢指针都用不了,这两个都是用于找到一段连续数组内数据为目标值的

  • 左右指针,此题和上题类似,多在外面加一个循环,每次使得内部的子数组里存在l,r有nums[l]+nums[l]=-nums[i]即可,则这个-nums[i]就是target

  • 不重复要求要有降重策略,从两个方面入手: 外侧i循环时不能重复; 内侧l和e更新时不能重复.

class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> res = new ArrayList<>();int n = nums.length;for(int i=0;i<n-2;i++){if(nums[i] >0) break;if(i>0 && nums[i] == nums[i-1]) continue;int l=i+1,r=n-1;while(l<r){int sum =  nums[i]+nums[l]+nums[r];if(sum == 0){res.add(Arrays.asList(nums[i],nums[l],nums[r]));while(r>l && nums[r] == nums[r-1]) r--;while(l<r && nums[l] == nums[l+1]) l++;r--;l++;}else if(sum > 0){r--;}else{l++;}}}return res;}
}

LCR 008. 长度最小的子数组 - 力扣(LeetCode)

  • 连续子数组 长度最小 目标和>=target 正整数数组

  • 连续子数组就要求不能sort

  • 连续子数组就可以用滑动窗口/快慢指针/前缀和 !!要注意这是正整数数组才能使用, 因为如果里面存在复数,那么该区间可能不是单调的,换言之可能会存在两个match的值,但是滑动窗口只会匹配到前一个值就返回,此时子数组并不是长度最小的

  • 滑动窗口/快慢指针: 此题的滑动窗口就是到当前的数组和,维护l,r->从l到r的数组和,每当该数组和>=target, 就记录当前长度并滑动窗口(将最左元素出窗口->sum-左指针数值,并左指针右移),直至两个指针都>数组长度为止

  • class Solution {public int minSubArrayLen(int target, int[] nums) {int n = nums.length;int l=0,r=0;int sum=0;int min_len = Integer.MAX_VALUE;while(l<n && r<n){sum+=nums[r];while(sum>=target){min_len = Math.min(min_len,r-l+1);sum-=nums[l];l++;}r++;}return min_len == Integer.MAX_VALUE ? 0 : min_len;}
    }

  • 前缀和+二分搜索: 前缀和也经常在求一段连续子数组之和时用到. 此解法的基础版本即维护一个前缀和, 并从0开始遍历到当前位置,查找是否存在一个前缀和使得当前前缀和-前缀和==target. 那么二分搜索就是优化遍历查找的方法->维护一个l=0,r=idx-1, 查找最后一个前缀和<=pre_sum[idx]-target即可

    • 查找最后一个<=target'的值, 这就要求二分搜索维护一个返回值ans,该返回值初始化为-1表示假设所有的数都>target'; 要把arr[mid]=target的情况与arr[mid]<target情况合并,这样就会收缩左边,找到更靠右的更大的<=target的值即最后一个<=target的位置,此时维护ans = mid

  • class Solution {public int minSubArrayLen(int target, int[] nums) {int n = nums.length;int[] pre_sum = new int[n+1];for(int i=1;i<=n;i++) pre_sum[i] = pre_sum[i-1]+nums[i-1];int min_len = Integer.MAX_VALUE;for(int r=n;pre_sum[r]>= target;r--){int need = pre_sum[r]-target;int l = binarySearch(pre_sum,need,r);min_len = l==-1 ? min_len : Math.min(min_len,r-l);}return min_len == Integer.MAX_VALUE ? 0 : min_len;}public int binarySearch(int[] pre_sum,int need,int end){int l=0,r = end-1;int ans = -1;while(l<=r){int m = (l+r)/2;if(pre_sum[m]<= need){ans = m;l = m+1;}else{r = m-1;}}return ans;}
    }

LCR 009. 乘积小于 K 的子数组 - 力扣(LeetCode)

  • 乘积<k 连续子数组 个数 正整数数组

  • 由于是乘积了,不合适用前缀积(乘积容易溢出),用滑动窗口更好

  • 要统计个数,又是连续的,那么从l到r一共有r-l+1个子数组

class Solution {public int numSubarrayProductLessThanK(int[] nums, int k) {int n = nums.length;int cnt = 0, cur_mul = 1;;for(int l=0,r=0;r<n;r++){cur_mul*=nums[r];while(l<=r && cur_mul>=k){cur_mul/=nums[l];l++;}cnt+=r-l+1;}return cnt;}
}

LCR 010. 和为 K 的子数组 - 力扣(LeetCode)

  • 和为k 连续子数组个数

  • 没有说是正整数数组,有要求是连续子数组,不能使用滑动窗口等

  • 使用map存储到当前idx为止的pre_sum和个数,计算cur_sum-target是否存在于map里,累加即可

class Solution {public int subarraySum(int[] nums, int k) {int n = nums.length;Map<Integer,Integer> map = new HashMap<>();int sum = 0,cnt = 0;map.put(0,1);for(int i=0;i<n;i++){sum+=nums[i];if(map.containsKey(sum-k)){cnt+=map.get(sum-k);}map.put(sum,map.getOrDefault(sum,0)+1);}return cnt;}
}

LCR 011. 连续数组 - 力扣(LeetCode)

  • 连续数组 找到含有相同数量的0和1

  • 怎么去判断当前01数量是否相同 !!将0标记为-1,每次计算从0到该索引的数据之和.记录在map里->当两个位置记录的数据相同时,即说明从i到j里01数相同,且为了获得最长连续子数组,只在map不含值的情况下才更新

class Solution {public int findMaxLength(int[] nums) {int n = nums.length;int sum=0,max_len = 0;Map<Integer,Integer> map = new HashMap<>();map.put(0,-1);for(int i=0;i<n;i++){sum += nums[i] == 0 ? -1 : 1;if(map.containsKey(sum)){max_len = Math.max(max_len,i-map.get(sum));//只要存在,维护最远的即最长时间未更新的,所以此时不需要put}else{map.put(sum,i);}}return max_len;}
}

LCR 012. 寻找数组的中心下标 - 力扣(LeetCode)

  • 中心下标左侧和=右侧和

  • 相当于要找一个下标,从0-i-1 和i+1到n的和相同,前缀和记录的就是0-j的和,那么0-i-1即pre_sum[i], i+1到n即pre_sum[n]-pre_sum[i+1]

class Solution {public int pivotIndex(int[] nums) {int n = nums.length;// int res = -1;int[] pre_sum = new int[n+1];for(int i=1;i<=n;i++){pre_sum[i] = pre_sum[i-1]+nums[i-1];}for(int i=0;i<n;i++){if(pre_sum[i] == pre_sum[n]-pre_sum[i+1]){return i;}}return -1;}
}

LCR 013. 二维区域和检索 - 矩阵不可变 - 力扣(LeetCode)

  • 子矩阵元素总和

  • 当调用次数过多,矩阵过大时,效率极低有概率超限, 所以要使用前缀和来优化,那么每次获得一段子数组的和时就可以通过前缀和相减来获得

class NumMatrix {
​int[][] num_matrix;int[][] pre_sum;
​public NumMatrix(int[][] matrix) {this.num_matrix = matrix;int n = matrix.length;int m = matrix[0].length;pre_sum = new int[n+1][m+1];for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){pre_sum[i][j] = pre_sum[i-1][j]+pre_sum[i][j-1]-pre_sum[i-1][j-1]+num_matrix[i-1][j-1];}}}public int sumRegion(int row1, int col1, int row2, int col2) {return pre_sum[row2+1][col2+1]-pre_sum[row2+1][col1]-pre_sum[row1][col2+1]+pre_sum[row1][col1];}
}

LCR 014. 字符串的排列 - 力扣(LeetCode)

  • 变位词 连续字串

  • 由于变位词无法去直接equal, 用的更多的就是滑动窗口, 来记录s1的窗口int[26] target_window 和s2的滑动窗口int[26] move_window, 当窗口大小为s1长度时,使用Arrays.equals(target_window,move_window)判断即可,相同则记录,不同则左侧收缩,左侧字母索引恢复

class Solution {public boolean checkInclusion(String s1, String s2) {int[] target = new int[26];int n=s1.length(), m = s2.length();for(int i=0;i<n;i++) target[s1.charAt(i)-'a']++;int[] window = new int[26];for(int l=0,r=0;r<m;r++){window[s2.charAt(r)-'a']++;if(r-l+1 == n){if(Arrays.equals(window,target)){return true;}window[s2.charAt(l)-'a']--;l++;}}return false;}
}

LCR 015. 找到字符串中所有字母异位词 - 力扣(LeetCode)

  • 所有异位词

  • 在上一题基础上记录起始索引即可

class Solution {public List<Integer> findAnagrams(String s, String p) {int n = s.length(), m = p.length();int[] p_window = new int[26];int[] move_window = new int[26];List<Integer> res = new ArrayList<>();for(int i=0;i<m;i++) p_window[p.charAt(i)-'a']++;for(int l=0,r=0;r<n;r++){move_window[s.charAt(r)-'a']++;if(r-l+1 == m){if(Arrays.equals(move_window,p_window)){res.add(l);}move_window[s.charAt(l)-'a']--;l++;}}return res;}
}

LCR 016. 无重复字符的最长子串 - 力扣(LeetCode)

  • 连续字串 无重复

  • 需要记录该字符是否出现过,则需要set/map来判重

  • set+滑动窗口: 当set里面没有s(r+1)时,adds(r+1)即可,如果存在,就记录当前最长ml,将s(l)移除set同时l右移即可

class Solution {public int lengthOfLongestSubstring(String s) {// 哈希集合,记录每个字符是否出现过Set<Character> occ = new HashSet<Character>();int n = s.length();// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动int rk = -1, ans = 0;for (int i = 0; i < n; ++i) {if (i != 0) {// 左指针向右移动一格,移除一个字符occ.remove(s.charAt(i - 1));}while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {// 不断地移动右指针occ.add(s.charAt(rk + 1));++rk;}// 第 i 到 rk 个字符是一个极长的无重复字符子串ans = Math.max(ans, rk - i + 1);}return ans;}
  • map+左右指针:map可以记录字符的索引,如果某时刻map.containsKey(s(r)),则将l移动到map.get(s(r))+1即可,要注意的是前提是这个idx>=l,才可更新l,否则l或许会左移变小,与之前的缩小窗口冲突,每次记录ml即可

class Solution {public int lengthOfLongestSubstring(String s) {int n = s.length();Map<Character,Integer> map = new HashMap<>();int max_len = 0;for(int l=0,r=0;r<n;r++){if(map.containsKey(s.charAt(r)) && map.get(s.charAt(r)) >= l){l = map.get(s.charAt(r))+1;}map.put(s.charAt(r),r);max_len = Math.max(max_len,r-l+1);}return max_len;}
}

http://www.dtcms.com/a/346318.html

相关文章:

  • CSS自定义属性(CSS变量)
  • 全面解析 `strncasecmp` 字符串比较函数
  • ES6变量与解构:let、const与模板字符串全解析
  • 53 C++ 现代C++编程艺术2-枚举和枚举类
  • 大麦盒子DM4036亲测刷包实践笔记
  • AI领域的语义空间是什么?
  • 波士顿房价线性回归预测讲解
  • 基于SpringBoot的家教信息预约管理系统【2026最新】
  • Spring IOC 原理与高级特性剖析
  • Redis---事务
  • 企业如何建立有效备份,防范病毒并快速恢复数据
  • UVM一些不常用的功能
  • 2公里级、高分辨率:新一代OCI重新定义光纤精准定位
  • huggingface离线下载模型使用方法
  • PiscCode使用 MediaPipe 检测人脸关键点多样展示
  • 域名地址是什么?
  • Python 异步框架 (Async/Aiohttp) 调用淘宝 API:实现万级商品数据异步采集
  • 透射TEM新手入门:衍射斑点标定 1
  • Java面试-== 和 equals() 方法的区别与实现原理
  • 结构-活性关系SAR中scaffold识别
  • MAPGIS6.7地质编录
  • Codeforces 一场真正的战斗
  • 线段树模版
  • 多态(polymorphism)
  • RS485通过NiMotion协议发送报文控制电机运行案例
  • 嵌入式学习日记(32)Linux下的网络编程
  • 全球教育数字化与人工智能应用现状扫描—不同教育阶段(学前、K12、高等教育、职业教育、成人教育)的应用差异与特点
  • Linux 软件包安装和管理的相关操作及使用总结(未完成)
  • 金蝶云星空·旗舰版 × 聚水潭跨境业务一体化集成方案
  • 速卖通、塔吉特采购自养号下单技术:打造自主可控的采购新方式