优选算法 - 1 ( 双指针 移动窗口 8000 字详解 )
一:双指针
1.1 移动零
题目链接:283.移动零
class Solution {public void moveZeroes(int[] nums) {for(int cur = 0, dest = -1 ; cur < nums.length ; cur++){if(nums[cur] == 0){}else{dest++; // dest 先向后移动⼀位int tmp = nums[cur];nums[cur] = nums[dest];nums[dest] = tmp;}}}
}
这类题目的本质就是数组划分,根据某个规则将数组分成若干个区间,在此题中,我们可以使用双指针算法划分数组的区间,用数组下标充当指针,两个指针会划分成3个区间
1.2 复写零
题目链接:复写零
class Solution {public void duplicateZeros(int[] arr) {int length = arr.length;int virtualLength = 0; // 虚拟长度,表示将所有 0 复写两次后的长度int lastIndex = 0; // 表示最后一个需要处理的索引// 第一步:确定最后一个需要处理的索引for (lastIndex = 0; lastIndex < length; lastIndex++) {virtualLength += (arr[lastIndex] == 0) ? 2 : 1; // 0 占两个位置,非 0 占一个位置if (virtualLength >= length) break; // 超过数组长度时停止}int dest = length - 1; // 目标位置,从数组最右端开始// 细节:如果最后一个复写数的索引的值刚好为 0,我们只需把 0 复制一次即可//因为如果正常来赋值的话,最后一个复写数的值为 0 时,我们只需把 0 复制一次即可,复制两次会造成越界,所以我们从右往左覆盖时也只需复制一次//virtualLength > length 保证了数组至少有一个 0 if (virtualLength > length && arr[lastIndex] == 0) {arr[dest--] = 0;lastIndex--; // 回退 lastIndex,继续处理前面的元素}// 第二步:从右向左复制元素while (lastIndex >= 0) {if (arr[lastIndex] == 0) {arr[dest--] = 0; // 复制第一个 0arr[dest--] = 0; // 复制第二个 0} else {arr[dest--] = arr[lastIndex]; // 复制非零元素}lastIndex--; // 移动到前一个元素}}
}
1.3 快乐数
题目链接:快乐数
class Solution {//封装一个求 n 每一位的平方和的函数public int bitsum(int n){int sum = 0;while(n > 0){int bit = n % 10;sum += bit * bit;n /= 10;}return sum;}public boolean isHappy(int n) {//先让快指针走一步int slow = n;int fast = bitsum(n);while(slow != fast){//慢指针走一步,快指针走两步slow = bitsum(slow);fast = bitsum(bitsum(fast));} return fast == 1;}
}
1.4 盛水最多的容器
题目链接: 盛水最多的容器
class Solution {public int maxArea(int[] height) {// left 是左指针, right 是右指针,ret存储最大的体积结果int left = 0;int right = height.length - 1;int ret = 0;while(left < right){int v = Math.min(height[left], height[right]) * (right - left);ret = Math.max(ret,v);if(height[left] < height[right]) left++;else right --;}return ret;}
}
1.5 有效三角形的个数
题目链接:有效三角形的个数
class Solution {public int triangleNumber(int[] nums) {//首先先对数组排序,并用 ret 存储有效三角形的个数Arrays.sort(nums);int ret= 0;int n = nums.length - 1;//先固定一个最大的数,最大的数最小的下标应该是 2,因为元素是有 3 个的for(int i = n ; i >= 2 ; i --){int left = 0;int right = i - 1;while (left < right) { //如果左指针加上右指针的值大于固定数的值if(nums[left] + nums[right] > nums[i]){ret += (right - left);right--;}else{left++;}} }return ret;}
}
1.6 和为 s 的两个数字
题⽬链接:和为s的两个数字
class Solution
{public int[] twoSum(int[] nums, int target){int left = 0, right = nums.length - 1;while(left < right){int sum = nums[left] + nums[right];if(sum > target) right--;else if(sum < target) left++;else return new int[] {nums[left], nums[right]};}// 照顾编译器return new int[]{0};}
}
1.7 三数之和
题目链接:三数之和
import java.util.*;class Solution {public List<List<Integer>> threeSum(int[] nums) {// 先对数组进行排序Arrays.sort(nums);List<List<Integer>> ret = new ArrayList<>();int n = nums.length;// 固定一个数,从左往右固定,最少保留两个数for (int i = 0; i < n - 2; i++) {// 跳过固定数的重复情况if (i > 0 && nums[i] == nums[i - 1]) continue;int left = i + 1, right = n - 1, target = -nums[i];while (left < right) {int sum = nums[left] + nums[right];if (sum > target) right--; else if (sum < target) left++;else {// 找到符合条件的三元组ret.add(Arrays.asList(nums[i], nums[left], nums[right]));left++; right--;// 跳过重复的 left 和 right 元素,防止结果重复while (left < right && nums[left] == nums[left - 1]) left++;while (left < right && nums[right] == nums[right + 1]) right--;}}}return ret;}
}
1.8 四数之和
题目链接:四数之和
import java.util.*;class Solution {public List<List<Integer>> fourSum(int[] nums, int target) {//先对数组进行排序Arrays.sort(nums);int n = nums.length;List<List<Integer>> ret = new ArrayList<>();//接着固定两个数for(int i = 0 ; i < n ;){for(int j = i + 1 ; j < n ; ){int left = j + 1 , right = n - 1;long aim = (long)target - nums[i] - nums[j];while(left < right){int sum = nums[left] + nums[right];if(sum > aim) right--;else if(sum < aim) left++;else{ret.add(Arrays.asList(nums[i], nums[j], nums[left++],nums[right--]));//接着进行去重while(left < right && nums[left] == nums[left - 1]) left++;while(left < right && nums[right] == nums[right + 1]) right--;}}//循环执行完毕后,让第二个固定的数加 1j++;while(j < n && nums[j] == nums[j - 1]) j++;}i++;while(i < n && nums[i] == nums[i - 1]) i++;}return ret;}
}
二: 移动窗口
2.1 长度最小的子数组
题目链接:长度最小的子数组
class Solution {public int minSubArrayLen(int target, int[] nums) {// size 用于记录最小子数组的长度,sum 用于存储子数组的和int n = nums.length, sum = 0, size = Integer.MAX_VALUE;int left = 0, right = 0;while(right < n){//进窗口sum += nums[right];//出窗口while(sum >= target){size = Math.min(size,right - left + 1);sum -= nums[left++];} //一次迭代完成后让右指针继续走right++;}//判断一下 size 是否被更新过return size == Integer.MAX_VALUE ? 0 : size;}
}
2.2 无重复字符的最长子串
题目链接:无重复字符的最长子串
class Solution {public int lengthOfLongestSubstring(String ss) {// 将字符串转换为字符数组char[] s = ss.toCharArray();// 用数组来模拟哈希表,记录字符出现次数int[] charCount = new int[128];int left = 0, maxLen = 0;for (int right = 0; right < s.length; right++) {char rightChar = s[right];// 将当前字符加入窗口,并更新计数,字符会自动转换为对应的 ascii 值charCount[rightChar]++;// 当出现重复字符时,缩小窗口直到没有重复字符while (charCount[rightChar] > 1) {char leftChar = s[left];charCount[leftChar]--; // 将左边的字符移出窗口left++;}// 更新最大无重复子串的长度maxLen = Math.max(maxLen, right - left + 1);}return maxLen;}
}
2.3 最大连续 1 的个数 III
题目链接:最大连续 1 的个数 III
class Solution {public int longestOnes(int[] nums, int k) {//定义左右指针和计数器 zero ,用于统计 0 的个数int left = 0, right = 0 ,zero = 0, n = nums.length, ret = 0;while(right < n){//进窗口if(nums[right] == 0) zero++;//出窗口while(zero > k){ if(nums[left++] == 0) zero--;}//每次循环都更新一下 ret ret = Math.max(ret,right - left + 1);right++;}return ret;}
}
2.4 将 x 减到 0 的最小操作数
题目链接:将 x 减到 0 的最小操作数
class Solution {public int minOperations(int[] nums, int x) {int sum = 0, left = 0, right = 0, n = nums.length;// 计算数组 nums 的总和for(int a : nums) sum += a;// 定义目标值 target(即我们希望找到一个子数组,使得它的和等于 sum - x)int target = sum - x;int total = 0; // 当前子数组的和int len = -1; // 子数组的最大长度,初始为 -1 表示不存在// 如果 target 小于 0,表示 x 比数组总和还大,不可能得到,直接返回 -1if (target < 0) return -1; // 使用滑动窗口在数组中寻找和为 target 的最长子数组while(right < n) {// 进窗口:将当前右边界的元素加入当前子数组的和total += nums[right];// 出窗口:当当前子数组的和大于 target 时,缩小窗口(从左边移出元素)while(total > target) total -= nums[left++];// 每次循环都要判断是否更新 len:当当前子数组的和等于 target 时,记录子数组的最大长度if(total == target) len = Math.max(len, right - left + 1);// 移动右边界,扩大窗口right++;}// 如果 len 仍为 -1,表示找不到符合条件的子数组,返回 -1// 否则,返回 n - len,表示需要移除的最小元素数目return (len == -1) ? -1 : n - len;}
}
2.5 水果成篮
题目链接:水果成篮
class Solution {public int totalFruit(int[] fruits) {//创建一个哈希表,用于存储水果的种类和数量Map<Integer, Integer> hash = new HashMap<>();int left = 0, right = 0, n = fruits.length, max = 0;while(right < n){//进窗口int ch1 = fruits[right];//通过 put 让 ch1 的值加一hash.put(ch1, hash.getOrDefault(ch1,0) + 1);//出窗口while(hash.size() > 2){int ch2 = fruits[left];//通过 put 让 ch2 的值减一hash.put(ch2, hash.get(ch2) - 1); //出窗口时,可能会让这个种类的数量变 0 ,此时要把这个种类踢出去if(hash.get(ch2) == 0) hash.remove(ch2);left++;}//每次循环都更新一下 max max = Math.max(max, right - left + 1);right++;}return max;}
}
2.6 找到字符串中所有字母异位词
题目链接:找到字符串中所有字母异位词
class Solution {public List<Integer> findAnagrams(String ss, String pp) {List<Integer> ret = new ArrayList<>();//不合理的情况,直接返回一个空的if(pp.length() > ss.length()) return ret;//接着把 ss 和 pp 转换为字符数组,并用 hash1 和 hash2 分别记录 s 和 p 中出现过的字符和次数,count 统计有效字符的个数char[] s = ss.toCharArray();char[] p = pp.toCharArray();int[] hash1 = new int[26];int[] hash2 = new int[26];for(int ch : p) hash2[ch - 'a']++;int left = 0, right = 0, count = 0, n = s.length;while(right < n){//进窗口 + 维护 countchar in = s[right];hash1[in - 'a']++;//进窗口后,如果 hash1 中的对应字符数量小于等于 hash2 中的数量,说明进入的是有效的字符if(hash1[in - 'a'] <= hash2[in - 'a']) count ++;//出窗口 + 维护 count,当窗口的宽度大于了 length 时,就要出窗口了 if(right - left + 1 > p.length) {char out = s[left];hash1[out - 'a']--;//出窗口后,如果 hash1 中对应的字符数量小于 hash2 中的数量,说明出的是有效的字符if(hash1[out -'a'] < hash2[out - 'a']) count--;left++;} //当 count 和 p 的长度相等时更新结果if(count == p.length) ret.add(left);right++;}return ret;}
}
2.7 串联所有单词的子串
题目链接:串联所有单词的子串
class Solution {public List<Integer> findSubstring(String s, String[] words) {List<Integer> ret = new ArrayList<>();if (words.length == 0 || s.length() < words.length * words[0].length()) return ret;// 存储 words 中每个字符串的频率Map<String, Integer> hash1 = new HashMap<>();for (String str : words) {hash1.put(str, hash1.getOrDefault(str, 0) + 1);}int len = words[0].length(), m = words.length, windowSize = len * m;// 遍历所有可能的起始点for (int i = 0; i < len; i++) {//每一次起始时,都用用一个新的 hash2 存储每个字符串的频率Map<String, Integer> hash2 = new HashMap<>();int left = i, right = i, count = 0;// 滑动窗口,要防止 right 走一步直接越界while (right + len <= s.length()) {String in = s.substring(right, right + len);right += len;// 更新窗口内单词频率计数hash2.put(in, hash2.getOrDefault(in, 0) + 1);// 如果 in 的频率不超过 hash1 中的频率,增加 countif (hash2.get(in) <= hash1.getOrDefault(in, 0)) {count++;}// 当窗口大小等于 windowSize 时出窗口if (right - left == windowSize) {if (count == m) ret.add(left); // 找到符合条件的子串String out = s.substring(left, left + len);left += len;// 更新窗口内单词频率计数if (hash2.get(out) <= hash1.getOrDefault(out, 0)) {count--;}hash2.put(out, hash2.get(out) - 1);// 如果频率为 0,从 hash2 中移除该单词if (hash2.get(out) == 0) {hash2.remove(out);}}}}return ret;}
}
2.8 最小覆盖子串
题目链接:最小覆盖子串
class Solution {public String minWindow(String ss, String tt) {// 将字符串转换成字符数组char[] s = ss.toCharArray();char[] t = tt.toCharArray();// 用 hash1 存储字符串 t 中每个字符的频率int[] hash1 = new int[128];int uniqueChars = 0; // 统计 t 中不同字符的种类数for (char ch : t) {if (hash1[ch]++ == 0) uniqueChars++;}// hash2 用来统计窗口内的字符频率int[] hash2 = new int[128];int minLen = Integer.MAX_VALUE, start = -1;int left = 0, matchedCount = 0;// 右指针移动for (int right = 0; right < s.length; right++) {char in = s[right];hash2[in]++;// 如果当前字符频率与 t 中相等,则增加匹配计数if (hash2[in] == hash1[in]) matchedCount++;// 当所有字符频率匹配时,尝试收缩窗口while (matchedCount == uniqueChars) {// 如果当前窗口更小,则更新最小窗口的长度和起始位置if (right - left + 1 < minLen) {minLen = right - left + 1;start = left;}// 出窗口char out = s[left++];if (hash2[out] == hash1[out]) matchedCount--;hash2[out]--;}}// 根据最小窗口的位置和长度返回结果return start == -1 ? "" : ss.substring(start, start + minLen);}
}
相关文章:

优选算法 - 1 ( 双指针 移动窗口 8000 字详解 )
一:双指针 1.1 移动零 题目链接:283.移动零 class Solution {public void moveZeroes(int[] nums) {for(int cur 0, dest -1 ; cur < nums.length ; cur){if(nums[cur] 0){}else{dest; // dest 先向后移动⼀位int tmp nums[cur];nums[cur] num…...

FairyGUI和Unity联动(入门篇)
一、FairyGUI编辑器中 1.新建按钮、新建组件 编辑器中界面简易设计如下 2.文件-发布设置-发布路径:自己unity项目Resources所在的路径 二、Unity 使用代码展示UI using FairyGUI; using System.Collections; using System.Collections.Generic; using UnityEngi…...

Go:文件输入输出以及json解析
文章目录 读取用户的输入文件读写读文件写文件 文件拷贝io包中接口的概念JSON 数据格式编码解码任意的数据: 读取用户的输入 从键盘和标准输入 os.Stdin 读取输入,最简单的办法是使用 fmt 包提供的 Scan… 和 Sscan… 开头的函数 看如下的程序 func t…...

编写红绿起爆线指标(附带源码下载)
编写需求: 想问问有没有能标注行情起爆点的指标。 效果展示: 红线上,出现绿柱转红柱做多。 蓝线下,出现红柱转绿柱做空。 源码展示(部分源码,完整源码需下载源码文件): IsMainIn…...

设计模式(四)装饰器模式与命令模式
一、装饰器模式 1、意图 动态增加功能,相比于继承更加灵活 2、类图 Component(VisualComponent):定义一个对象接口,可以给这些对象动态地添加职责。ConcreteComponent(TextView):定义一个对象,可以给这个对象添加一…...

Android11 修改系统语言
1.定义一个view <RelativeLayoutandroid:id"id/rlChooseLanguage"style"style/SettingAboutItem"><TextViewstyle"style/SettingAboutItemTextView"android:text"string/choose_language" /><ImageView style"st…...

vue3 查看word pdf excel文件
也是在网上找的基础上修改的 可以直接使用 npm install vue-office/docx npm install vue-office/excel npm install vue-office/pdf<template><divclass"Office-Preview"v-loading"loading"element-loading-text"文件加载中...">…...

java八股-垃圾回收机制-垃圾回收算法,分代回收,垃圾回收器
文章目录 垃圾回收算法引用计数法可达性分析算法 jvm垃圾回收算法标记清除算法标记整理算法复制算法本章总结 JVM中的分代回收本章总结 JVM有哪些垃圾回收器?1.串行垃圾收集器2.并行垃圾收集器3.CMS(并发)垃圾收集器本章小结 详细聊一下G1垃圾…...

iSCSI 和FC的概述
一、技术基础与架构 iSCSI 技术基础:iSCSI是基于TCP/IP协议的存储网络协议,它实现了在IP网络上运行SCSI协议。架构:iSCSI协议栈包括SCSI层、iSCSI层、TCP/IP层等,通过标准的以太网技术实现存储数据的传输。 FC 技术基础࿱…...

一文了解Android中的AudioFlinger
AudioFlinger 是 Android 音频框架中的一个核心组件,负责管理音频流的混合和输出。它是 Android 音频系统服务的一部分,作为音频框架和硬件之间的桥梁,接收应用程序的音频请求、进行混音处理,并最终通过音频硬件输出声音。 
超全面!一文带你快速入门HTML,CSS和JavaScript!
作为一名后端程序员,在开发过程中避免不了和前端打交道,所以就要了解一些前端的基础知识,比如三剑客HTML,CSS,JavaScript,甚至有必要学习一下Vue、React等前端主流框架。 学习文档:https://www.w3school.com.cn/ 一…...

C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
题目: 题解: char* reverseWords(char* s) {int length strlen(s);char* ret (char*)malloc(sizeof(char) * (length 1));ret[length] 0;int i 0;while (i < length) {int start i;while (i < length && s[i] ! ) {i;}for (int p …...

408笔记合集
操作系统 《王道操作系统》-BitHachi 计算机网络 《王道计算机网络》--BitHachi 组成原理 《王道计算机组成原理》--BitHachi...

智慧医疗:纹理特征VS卷积特征
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...

OPC学习笔记
一. 解决使用milo读取OPC设备字符串类型时,出现中文和特殊符号乱码的情况 解决前,读取字符串:你好 2. 解决后,读取字符串:你好 3. 解决前,读取字符串:165℃ 解决后,读取字符串&am…...

数据结构的时间复杂度和空间复杂度
目录 时间复杂度 空间复杂度 时间复杂度 基本操作的执行次数,为时间复杂度。 我们使用大O的渐进表示法来表示时间复杂度。 怎么使用? 先看例子: 在这个例子中, 基本操作为变量 count 的 加加 操作,并且,执行…...

HBase理论_背景特点及数据单元及与Hive对比
本文结合了个人的笔记以及工作中实践经验以及参考HBase官网,我尽可能把自己的知识点呈现出来,如果有误,还请指正。 1. HBase背景 HBase作为面向列的数据库运行在HDFS之上,HDFS缺乏随机读写操作,HBase正是为此而出现。…...

生产模式打包
在生产模式下打包 Node.js 和前端(例如 Vue 或 React)应用时,通常需要对代码进行优化,使其在生产环境中运行更高效。以下是如何在生产模式下配置和打包项目的步骤: 1. Node.js 生产模式打包 Node.js 本身不需要像前端…...

Vue的路由
Vue的路由 出发点:遇到多页面网页的反复跳转,有些繁琐,可以通过Vue的路由实现单页面中数据的变化 实现单页面中数据的变化(通过Vue-router来进行操作的,数据的请求获取也需要ajax异步交互),具…...

Spring框架之策略模式 (Strategy Pattern)
策略模式(Strategy Pattern)详解 策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列算法,并将每种算法封装到独立的策略类中,使它们可以相互替换,从而使算法的变化独…...

探索Google Earth Engine:利用MODIS数据和R语言进行2000-2021年遥感生态指数(RSEI)的时空趋势分析
前段时间,小编学习了在GEE上进行遥感生态指数(RSEI)的评估,非常头疼,但是实验了两周后,亲测有效,主要采用的是MODIS数据分析了2000-2021年中国内蒙古某地的RSEI时间序列分布状况,现在把学习的代码分享给大家。 1 GEE计算RSEI 1.1研究区域导入与初步定义 var sa = ee…...

多商户中英双语电商系统设计与开发 PHP+mysql
随着全球电商市场的扩展,多商户平台成为了越来越多商家参与全球贸易的重要方式。为了适应不同语言用户的需求,尤其是中英双语用户的需求,设计一个支持中英双语的电商系统显得尤为重要。本文将重点探讨如何设计一个多商户中英双语电商系统&…...

牵手App红娘专属1V1服务,打造贴心交友指导
对于年轻一代而言,婚恋方式已明显区别于传统,他们更倾向于直接、活泼的交流方式,享受着在轻松愉快的氛围中边玩边交友的乐趣。线上社交平台,尤其是那些基于兴趣构建的交友模式,正逐渐成为他们探索爱情、寻找共鸣的新舞…...

论文解析:边缘计算网络中资源共享的分布式协议(2区)
目录 论文解析:边缘计算网络中资源共享的分布式协议(2区) 核心内容: 核心创新点的原理与理论: 多跳边缘计算场景 一、边缘计算的基本概念 二、多跳边缘计算场景的含义 三、多跳边缘计算场景的应用 四、多跳边缘计算场景的优势 论文解析:协作边缘计算网络中资源共…...

Android Osmdroid + 天地图 (一)
Osmdroid 天地图 前言正文一、配置build.gradle二、配置AndroidManifest.xml三、获取天地图的API Key① 获取开发版SHA1② 获取发布版SHA1 四、请求权限五、显示地图六、源码 前言 Osmdroid是一款完全开源的地图基本操作SDK,我们可以通过这个SDK去加一些地图API&am…...

浅谈:基于三维场景的视频融合方法
视频融合技术的出现可以追溯到 1996 年 , Paul Debevec等 提出了与视点相关的纹理混合方法 。 也就是说 , 现实的漫游效果不是从摄像机的角度来看 , 但其仍然存在很多困难 。基于三维场景的视频融合 , 因其直观等特效在视频监控等相关领域有着…...

PostgreSQL序列:创建、管理与高效应用指南
一、引言 在PostgreSQL中,序列(Sequence)是一种用于生成唯一标识符的数据库对象。它们常常被用于为主键字段提供连续且唯一的值,特别是在创建新记录时。序列提供了一种机制,能够确保每次调用都能返回一个唯一的值&…...

部署安装jdk8\redis\mysql8\nginx
安装jdk8 linux安装jdk8详细步骤_linux jdk8安装-CSDN博客 安装redis 安装redis 后台启动命令 cd /ra/redis-6.0.0/src ./redis-server --daemonize yes安装mysql8.0(自定义目录安装) 1、创建自己的mysql-8.0,解压mysql安装包 tar -zxv…...

重要通知:Sedex 旧平台即将关闭
我们正在对 Sedex 平台进行一些重要更新,这些更新将更好地提升您的用户体验。 作为更新计划的⼀部分,我们将在 2025 年 2 ⽉关闭 Sedex Advance 平台(即,Sedex 旧平台)。旧平台的⼀些功能将转移到当前的平台上。这些改…...

Windows配置NTP时间同步
Windows下实现NTP时间同步 1、Windows时间服务(W32Time)2、Windows 时间同步的工作原理3、配置和管理 Windows 时间同步3.1 命令行工具:w32tm3.2 控制面板中的设置 4. 高级设置(Windows Server 环境)5.调整时间同步的间隔5.1 通过组策略调整时…...