面试手撕算法高频专题:数组的双指针思想及应用(算法村第三关白银挑战)

所谓的双指针其实就是两个变量,不一定真的是指针。

  1. 快慢指针:一起向前走
  2. 对撞指针、相向指针:从两头向中间走
  3. 背向指针:从中间向两头走

移除值为val的元素

题目描述

27. 移除元素 - 力扣(LeetCode)

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,3,0,4]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

快慢指针

/*** @return 移除后val后数组的新长度*/
public int removeElement(int[] nums, int val)
{int slow = 0;for (int fast = 0; fast < nums.length; fast++){//nums[fast] == val时slow等待,直到下一个nums[fast](!= val),然后将nums[slow]覆盖if (nums[fast] != val){nums[slow] = nums[fast];slow++; //slow移动到下一个待写位置}}return slow;
}

在这里插入图片描述

上图的val=2

对撞指针+交换

/*** 核心思想:从右侧找到不是val的值来顶替左侧是val的值*/
public int removeElement(int[] nums, int val)
{int left = 0;int right = nums.length - 1;while (left <= right){if(nums[left] == val && nums[right] != val){int temp = nums[left];nums[left] = nums[right];   //覆盖删除nums[right] = temp; //交换的目的是让right指针能够移动}//更新指针if (nums[left] != val)left++;if (nums[right] == val)right--;}return left;
}

在这里插入图片描述

对撞指针+覆盖

public int removeElement(int[] nums, int val)
{int left = 0;int right = nums.length - 1;while (left <= right){if (nums[left] == val){nums[left] = nums[right];right--;}elseleft++;}return right + 1;
}

在这里插入图片描述

删除有序数组中的重复项

题目描述

26. 删除有序数组中的重复项 - 力扣(LeetCode)

给你一个 非严格递增排列 的数组 nums ,请你** 原地** 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示:

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 非严格递增 排列

快慢指针

public int removeDuplicates(int[] nums)
{int slow = 0;for(int fast = 0; fast < nums.length; fast++){//fast往下走,直到指向第一个与slow不同的元素if(nums[fast] != nums[slow]){slow++; //slow后移一位,存储新的不重复元素nums[slow] = nums[fast];}}return slow + 1;    //返回nums中唯一元素的个数。
}

在这里插入图片描述

进阶:重复元素保留k个

  • k 位直接保留
  • **fast 不断向后遍历, nums[fast] 能够保留的前提是与nums[slow]**的前面第 k 个元素不同
  • 保留后 slow 指向新的写入位置
public int removeDuplicates(int[] nums)
{int slow = 0;int k = 2;  //重复元素保留k个for(int fast = 0; fast < nums.length; fast++){if(slow < k  || nums[slow - k] != nums[fast]){nums[slow] = nums[fast];slow++;}}return slow;    //返回nums中唯一元素的个数。
}

按奇偶排序数组

题目描述

905. 按奇偶排序数组 - 力扣(LeetCode)

给你一个整数数组 nums,将 nums 中的的所有偶数元素移动到数组的前面,后跟所有奇数元素。

返回满足此条件的 任一数组 作为答案。

示例 1:

输入:nums = [3,1,2,4]
输出:[2,4,3,1]
解释:[4,2,3,1][2,4,1,3][4,2,1,3] 也会被视作正确答案。

示例 2:

输入:nums = [0]
输出:[0]

对撞指针+交换

public int[] sortArrayByParity(int[] nums)
{int left = 0;int right = nums.length - 1;while (left < right){//左奇右偶时两边交换,把奇数调到后面,偶数调到前面if(nums[left] % 2 == 1  && nums[right] % 2 == 0){int t = nums[left];nums[left] = nums[right];nums[right] = t;}if(nums[left] % 2 == 0) left++; //跳过左边的偶数if(nums[right] % 2 == 1) right--; //跳过右边的奇数}return nums;
}

数组轮转

题目描述

189. 轮转数组 - 力扣(LeetCode)

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1: [7,1,2,3,4,5,6]
向右轮转 2: [6,7,1,2,3,4,5]
向右轮转 3: [5,6,7,1,2,3,4]

示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1: [99,-1,-100,3]
向右轮转 2: [3,99,-1,-100]

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 105

进阶:

  • 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
  • 你可以使用空间复杂度为 O(1)原地 算法解决这个问题吗?

三次翻转

public void rotate(int[] nums, int k)
{//举例nums:[1,2,3,4,5,6,7]k = k % nums.length;reverse(nums,0, nums.length - 1);	//nums:[7,6,5,4,3,2,1]reverse(nums,0,k-1);	//nums:[5,6,7,4,3,2,1]reverse(nums,k, nums.length - 1);	//nums:[5,6,7,1,2,3,4]
}//反转指定区间
public void reverse(int[] nums, int left, int right)
{while (left < right){int t = nums[left];nums[left] = nums[right];nums[right] = t;left++;right--;}
}

数组的区间专题

汇总区间

题目描述

228. 汇总区间 - 力扣(LeetCode)

给定一个 无重复元素有序 整数数组 nums

返回 恰好覆盖数组中所有数字最小有序 区间范围列表* 。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x

列表中的每个区间范围 [a,b] 应该按如下格式输出:

  • "a->b" ,如果 a != b
  • "a" ,如果 a == b

示例 1:

输入:nums = [0,1,2,4,5,7]
输出:["0->2","4->5","7"]
解释:区间范围是:
[0,2] --> "0->2"
[4,5] --> "4->5"
[7,7] --> "7"

示例 2:

输入:nums = [0,2,3,4,6,8,9]
输出:["0","2->4","6","8->9"]
解释:区间范围是:
[0,0] --> "0"
[2,4] --> "2->4"
[6,6] --> "6"
[8,9] --> "8->9"

提示:

  • 0 <= nums.length <= 20
  • -231 <= nums[i] <= 231 - 1
  • nums 中的所有值都 互不相同
  • nums 按升序排列
  1. slow 指向每个区间的起始位置, fastslow 位置开始向后遍历,直到不满足连续递增或 fast 达到数组边界。当前区间结束
  2. slow 指向更新为 fast + 1,作为下一个区间的开始位置,fast继续向后遍历找下一个区间的结束位置,如此循环,直到 nums 遍历完毕

append(char c):将指定的字符添加到当前StringBuilder对象的末尾。如果参数是数字,则自动转为字符

public List<String> summaryRanges(int[] nums)
{ArrayList<String> ans = new ArrayList<>();int slow = 0;int fast = 0;for (; fast < nums.length; fast++){if(fast == nums.length - 1 || nums[fast]+1 != nums[fast + 1]){StringBuilder sb = new StringBuilder();sb.append(nums[slow]);if(nums[slow] != nums[fast])sb.append("->").append(nums[fast]);ans.add(sb.toString());slow = fast + 1;}}return ans;
}

缺失的区间

题目描述

163. 缺失的区间 - 力扣(LeetCode)

给你一个闭区间 [lower, upper] 和一个 按从小到大排序 的整数数组 nums ,其中元素的范围在闭区间 [lower, upper] 当中。

如果一个数字 x[lower, upper] 区间内,并且 x 不在 nums 中,则认为 x 缺失

返回 准确涵盖所有缺失数字最小排序 区间列表。也就是说,nums 的任何元素都不在任何区间内,并且每个缺失的数字都在其中一个区间内。

示例 1:

输入: nums = [0, 1, 3, 50, 75], lower = 0 , upper = 99
输出: [[2,2],[4,49],[51,74],[76,99]]
解释:返回的区间是:
[2,2]
[4,49]
[51,74]
[76,99]

示例 2:

输入: nums = [-1], lower = -1, upper = -1
输出: []
解释: 没有缺失的区间,因为没有缺失的数字。

提示:

  • -109 <= lower <= upper <= 109
  • 0 <= nums.length <= 100
  • lower <= nums[i] <= upper
  • nums 中的所有值 互不相同
public List<List<Integer>> findMissingRanges(int[] nums, int lower, int upper)
{List<List<Integer>> missingRanges = new ArrayList<>();//[lower, upper]缺失if (nums.length == 0){missingRanges.add(generateRange(lower, upper));return missingRanges;}//[lower, nums[0] - 1]缺失if (nums[0] > lower){missingRanges.add(generateRange(lower, nums[0] - 1));}//i = 0起,[nums[i] + 1, nums[i + 1] - 1]缺失for (int i = 0; i < nums.length - 1; i++){if(nums[i + 1] - nums[i] > 1)	//非连续递增{missingRanges.add(generateRange(nums[i] + 1, nums[i + 1] - 1));}}//[nums[length - 1] + 1, upper]缺失if (nums[nums.length - 1] < upper){missingRanges.add(generateRange(nums[nums.length - 1] + 1, upper));}return missingRanges;	//返回所有缺失区间
}//生成区间
public List<Integer> generateRange(int start, int end)
{ArrayList<Integer> range = new ArrayList<>();range.add(start);range.add(end);return range;
}

字符串替换空格

题目描述

(剑指offer)请实现一个函数,将一个字符串中的每个空格替换成**“%20”。例如,“We Are Happy.”** 经过替换之后为**“We%20Are%20Happy.”**

public class replaceSpaces
{public static void main(String[] args){String str1 = replaceSpace_immutable("We Are Happy.");System.out.println(str1);    //We%20Are%20Happy.(正确)StringBuffer sb = new StringBuffer("We Are Happy.");String str2 = replaceSpace_variable(sb);System.out.println(str2);   //We%20Are%20Happy.(正确)}//存储字符串的空间不可变,或者存储空间不算大public static String replaceSpace_immutable(String str){String res = "";for (int i = 0; i < str.length(); i++){char c = str.charAt(i);if (c == ' ')res = res + "%20";elseres = "%s%s".formatted(res, c); //效果相同}return res;}//存储字符串的空间可变,或者存储空间很大public static String replaceSpace_variable(StringBuffer str){int blank = 0;  //str中的空格数//计算空格数for (int i = 0; i < str.length(); i++)if (str.charAt(i) == ' ')blank++;int fast = str.length() - 1;    //fast指向原长度的末尾//设置新的长度(StringBuffer才有的方法,String没有)str.setLength(str.length() + 2 * blank);int slow = str.length() - 1;    //slow指向新长度的末尾while (fast >=0 && fast < slow){char c = str.charAt(fast);if (c == ' '){str.setCharAt(slow,'0');	//复制slow--;str.setCharAt(slow,'2');slow--;str.setCharAt(slow,'%');}elsestr.setCharAt(slow, c);fast--;slow--;}return str.toString();}
}

replaceSpace_variable图解

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/589012.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【更新】cyのMemo(20231231~)

序言 最终&#xff0c;无事发生&#xff0c;我的跨年是在图书馆&#xff08;因为我忘带卡打不开实验室门&#xff09;&#xff0c;和去年一样。其实我并不想去图书馆&#xff0c;但是觉得在床上跨年太颓废&#xff0c;找个好点的处所&#xff0c;至少说得过去些。人嘛&#xf…

12.31_黑马数据结构与算法笔记Java

目录 345 设计跳表 Leetcode 1206 346 设计最小栈 Leetcode 155 347 设计端网址 Leetcode 355 348 设计推特 Leetcode 355 349 股票系列问题 Leetcode 121 350 股票系列问题 Leetcode 122 351 股票系列问题 Leetcode 714 352 股票系列问题 Leetcode 309 353 股票系列问…

【CISSP学习笔记】6. 安全开发

该知识领域涉及如下考点&#xff0c;具体内容分布于如下各个子章节&#xff1a; 理解安全并将其融入软件开发生命周期 (SDLC) 中在软件开发环境中识别和应用安全控制评估软件安全的有效性评估获得软件对安全的影响定义并应用安全编码准则和标准 6.1. 系统开发控制 6.1.1. 软…

以太网转RS485通讯类库封装

最近选用有人科技的以太网转RS485模块做项目&#xff0c;设备真漂亮&#xff0c;国货之光。调通了通讯的代码&#xff0c;发到网上供大家参考&#xff0c;多多交流。 以下分别是配套的头文件与源文件&#xff1a; /*******************************************************…

EOS开发Ubuntu安装EOSIO.CDT(Install the EOSIO.CDT)

EOS开发Ubuntu安装EOSIO.CDT&#xff08;Install the EOSIO.CDT&#xff09; EOSIO.CDT介绍&#xff1a;EOSIO合约开发工具包&#xff0c;简称CDT&#xff0c;是与合约编译相关的工具集合。而且后续教程主要使用 CDT 来编译合约和生成 ABI&#xff0c;不要忽略。 刚才我们安装好…

【数值分析】LU分解解Ax=b,matlab自己编程实现

LU分解&#xff08;直接三角分解&#xff0c;Doolittle分解&#xff09; A x b , A L U Axb \,\,,\,\, ALU Axb,ALU { L y b U x y \begin{cases} Lyb \\ Uxy \end{cases} {LybUxy​ 矩阵 L {L} L 的对角元素为 1 {1} 1 &#xff0c;矩阵 U {U} U 的第一行和 A {A} A …

Octave处理高斯光束

文章目录 读取图像截取感兴趣区域强度图拟合 Octave是一种开源的数值计算软件&#xff0c;主要用于科学计算、数据分析和数值模拟等领域。既提供了一个用户友好的命令行界面&#xff0c;使用户能够通过输入简单的命令来进行各种数学运算和数据操作。也提供了功能完备的GUI窗口&…

关于LayUI表格重载数据问题

目的 搜索框搜索内容重载数据只显示搜索到的结果 遇到的问题 在layui官方文档里介绍的table属性有data项,但使用下列代码 table.reload(test, {data:data //data为json数据}); 时发现&#xff0c;会会重新调用table.render的url拿到原来的数据&#xff0c;并不会显示出来传…

go切片截取细节分析

切片截取&#xff0c;有没有很迷&#xff1f; 目录 典型截取&#xff08;两参数、三参数&#xff09;及分析 迷之append参与截取及细节分析 关于截取时的初始索引是否从第一个位置开始的影响 修改原切片细节分析 典型截取&#xff08;两参数、三参数&#xff09;及分析 先…

看懂基本的电路原理图(入门)

文章目录 前言一、二极管二、电容三、接地一般符号四、晶体振荡器五、各种符号的含义六、查看原理图的顺序总结 前言 电子入门&#xff0c;怎么看原理图&#xff0c;各个图标都代表什么含义&#xff0c;今天好好来汇总一下。 就比如这个电路原理图来说&#xff0c;各个符号都…

文件监控-IT安全管理软件

文件监控和IT安全管理软件是用于保护企业数据和网络安全的工具。这些工具可以帮助企业监控文件的变化&#xff0c;防止未经授权的访问和修改&#xff0c;并确保数据的安全性和完整性。 一、具有哪些功能 文件监控软件可以实时监控文件系统的活动&#xff0c;包括文件的创建、修…

L1-076:降价提醒机器人

题目描述 小 T 想买一个玩具很久了&#xff0c;但价格有些高&#xff0c;他打算等便宜些再买。但天天盯着购物网站很麻烦&#xff0c;请你帮小 T 写一个降价提醒机器人&#xff0c;当玩具的当前价格比他设定的价格便宜时发出提醒。 输入格式&#xff1a; 输入第一行是两个正整数…

条款13:以对象管理资源

文章目录 没有管理的情况解决办法之unique_ptr智能指针解决办法之shared_ptr智能指针总结 没有管理的情况 资源是指一旦你使用完它&#xff0c;就需要返回系统的东西。 class Investment { ... }; // 投资类型层次结构的基类 Investment* createInvestment(); // 工厂函数&…

2022–2023学年2021级计算机科学与技术专业数据库原理 (A)卷

一、单项选择题&#xff08;每小题1.5分&#xff0c;共30分&#xff09; 1、构成E—R模型的三个基本要素是&#xff08; B &#xff09;。 A&#xff0e;实体、属性值、关系 B&#xff0e;实体、属性、联系 C&#xff0e;实体、实体集、联系 D&#xff0e;实体、实体…

html-css-js移动端导航栏底部固定+i18n国际化全局

需求&#xff1a;要做一个移动端的仿照小程序的导航栏页面操作&#xff0c;但是这边加上了i18n国家化&#xff0c;由于页面切换的时候会导致国际化失效&#xff0c;所以写了这篇文章 1.效果 切换页面的时候中英文也会跟着改变&#xff0c;不会导致切换后回到默认的语言 2.实现…

oracle 9i10g编程艺术-读书笔记1

根据书中提供的下载代码链接地址&#xff0c;从github上找到源代码下载地址。 https://github.com/apress下载好代码后&#xff0c;开始一段新的旅行。 设置 SQL*Plus 的 AUTOTRACE 设置 SQL*Plus 的 AUTOTRACE AUTOTRACE 是 SQL*Plus 中一个工具&#xff0c;可以显示所执行…

Python-Selenium 调用 JavaScript

当前环境&#xff1a; Windows 10 Python 3.7 selenium3.141.0 urllib31.26.2 Chromium 65.0.3312.0 &#xff08;32 位&#xff09; 在 WebDriver 中提供了执行 JavaScript 的方法&#xff1a; execute_script(script, *args)&#xff0c;JavaScript 代码以字符串的形式…

分布式数据库事务故障恢复的原理与实践

关系数据库中的事务故障恢复并不是一个新问题&#xff0c;自70年代关系数据库诞生之后就一直伴随着数据库技术的发展&#xff0c;并且在分布式数据库的场景下又遇到了一些新的问题。本文将会就事务故障恢复这个问题&#xff0c;分别讲述单机数据库、分布式数据库中遇到的问题和…

Java Bean Validation API

API 默认包&#xff1a;javax.validation。 Validator 基础接口&#xff1a;javax.validation.Validator。 public interface Validator {/** 验证 object*/<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups);/** 验证属性…

华为商城秒杀时加密验证 device_data 的算法研究

前言 之前华为商城放出 Mate60 手机时, 想给自己和家人抢购一两台&#xff0c;手动刷了好几天无果后&#xff0c;决定尝试编写程序&#xff0c;直接发送 POST 请求来抢。通过抓包和简单重放发送后&#xff0c;始终不成功。仔细研究&#xff0c;发现 Cookie 中有一个名为 devic…