算法第一弹-----双指针

news2024/12/27 5:16:43

目录

1.移动零

2.复写零

3.快乐数

4.盛水最多的容器

5.有效三角形的个数

6.查找总价值为目标值的两个商品

7.三数之和

8.四数之和


双指针通常是指在解决问题时,同时使用两个指针(变量,常用来指向数组、链表等数据结构中的元素位置),通过对这两个指针的移动和操作来高效地处理数据、查找元素、遍历结构等,从而达到降低时间复杂度、优化算法的目的。

 

根据指针移动的方向和规则不同,双指针可以大致分为以下两类:

  • 同向双指针
    两个指针起始位置可能相同或者不同,但它们朝着同一个方向移动,比如都从数组头部向尾部移动,常用于处理需要连续遍历部分区间、查找满足特定条件的子区间等问题。常使用快慢指针

  • 对撞双指针
    两个指针分别从数据结构(常见的如数组、字符串等)的两端开始,然后相向而行,朝着彼此靠近的方向移动,这种方式常常应用在判断回文、两数之和类问题(当数据有序时)等场景中。

1.移动零

283. 移动零 - 力扣(LeetCode)


题目描述:

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。


示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

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

解法:(使用快排的思想,将数组划分区间)

算法思路:

1.我们使用两个指针(left,right),规定left左边区域为非零的数字,right去向后扫描,遇到非零的数字,先让left++,然后再让left和right所指下标的数字进行交换,这样就保证了当right扫描完整个数组时,left左边(包括left)的区域全是非零的数字

2.left初始化为-1,是因为left指向的是非零元素的最后一个位置,刚开始我们并不知道最后一个非零元素在哪,所以初始化为-1,right是用来扫描的,所以初始化为0


JAVA算法代码:

class Solution {
    public void moveZeroes(int[] nums) {
        int left=-1;
        int right=0;
        for(;right<nums.length;right++){
if(nums[right]!=0){
left++;
int tmp=nums[left];
nums[left]=nums[right];
nums[right]=tmp;
}
        }
    }
}

2.复写零

1089. 复写零 - 力扣(LeetCode)


题目描述:

给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。


示例 1:

输入:arr = [1,0,2,3,0,4,5,0]
输出:[1,0,0,2,3,0,0,4]
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]

示例 2:

输入:arr = [1,2,3]
输出:[1,2,3]
解释:调用函数后,输入的数组将被修改为:[1,2,3]

解法:分三步,第一步找到最后一个要复写的元素,第二步处理一下边界情况,第三步从后往前遍历数组,依次填写出复写后的结果

算法思路

1.使用cur去遍历数组,dest去确定最后一个复写元素的位置,cur初始化为0,dest初始化为-1

2.使用cur遍历数组,当cur所指元素不为0时,dest++,当cur所指元素为0时dest+=2;并且每次循环判断dest是否到达数组的最后一个位置或超出数组,如果dest>=arr.length-1,那么就找到了最后一个要复写的元素,直接break跳出循环

3.当最后一个要复写的元素是0时,且dest处在数组的倒数第二个位置,这时,dest就会向后走两格,就会造成数组越界,其他情况均不会造成数组越界

4.面对数组越界这种情况,我们在从后往前填写复写结果时,需要做一下边界处理,当dest为n时,也就是越界了,因为此时一定是最后一个复写元素是0,我们需要将数组的最后一个元素设为0,然后dest-=2,cur--

5.从后往前复写,当cur所指元素为0时,dest位置设置为0,dest-1位置也设置为0,dest-=2,cur--

当cur所指元素不为0时,将dest位置设置为cur所指元素,dest--,cur--,当cur<0时,也就是cur从后往前遍历完毕,复写操作也就完毕了


JAVA算法代码:

class Solution {
    public void duplicateZeros(int[] arr) {
        int dest=-1;
        int cur=0;
        int n=arr.length;
//找到要的结果的最后一个位置
    while(dest<n){
if(arr[cur]==0)dest+=2;
else dest++;
if(dest>=n-1)break;
cur++;
    }
//处理边界情况
    if(dest==n){
        arr[n-1]=0;
        cur--;
        dest-=2;
    }
//从后往前写
while(cur>=0){
if(arr[cur]==0){
    arr[dest--]=0;
    arr[dest--]=0;
}else{
    arr[dest--]=arr[cur];
}
cur--;
}
    }
}

3.快乐数

202. 快乐数 - 力扣(LeetCode)


题目描述:

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false


示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

解法:快慢指针,判断相遇时的值是否为1

算法思路

1.题目中给出的数据范围是1 <= n <= 2的31次方 - 1,2的31次方是一个10位数的数字,我们以9999999999的平方和来算,也就是810,那么在这个数据范围内的所有数据的平方和也就在1~810这个范围

2.根据鸽巢原理,当我们计算到第811个平方和时,就必然会陷入的一个循环

3.在这个循环里面,通过快慢指针,找到快慢指针相遇时的值,判断是否为1,如果为1,那么这个数就是快乐数,如果不为1,那么这个数就不是快乐数

4.快指针每次计算两次平方和,慢指针每次计算一次平方和;当快指针与慢指针相遇时,但相遇时的值不为1,这个数一定不是快乐数,这是因为快指针往后走的过程中,如果他有一次的平方和为1,那么他后面所有的平方和一定就都为1,陷入了一个1的循环,当快慢指针相遇时的结果不为1,说明快指针在走的过程中没有一次的平方和是1,就可以判定他必然不是快乐数


JAVA算法代码:

class Solution {
//计算平方和
public int quaSum(int n){
int sum=0;
while(n!=0){
int x=n%10;
sum+=x*x;
n/=10;
}
return sum;
}

    public boolean isHappy(int n) {
        int fast=quaSum(n);
        int slow=n;
while(slow!=fast){
fast=quaSum(quaSum(fast));
slow=quaSum(slow);
}
return slow==1;
    }
}

4.盛水最多的容器

11. 盛最多水的容器 - 力扣(LeetCode)


题目描述

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。


示例 1:

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

解法:(对撞指针)

算法思路

1.使用两个指针(left,right)分别指向这个容器的两端,计算容器的大小,通过移动指针,找到最大的容器

2.当移动指针宽度是一定减小的,此时如果再移动高的一边(也就是较高高度一边的指针),那么容器的大小一定是减小的,容器的大小是由宽度和较小一边的高度决定的,移动指针时,只能移动较矮一边的指针

3.新的容器大小和之前的最大的容器大小比较,如果比之前大,就将之前的最大容器修改为新的容器大小,否则继续计算下一个容器的大小,直到两个指针相遇,返回最大的容器大小


JAVA算法代码

class Solution {
    public int maxArea(int[] height) {
        int left=0;
        int right=height.length-1;
        int ret=0;
        int v=0;
        while(left<right){
v=Math.min(height[left],height[right])*(right-left);
ret=Math.max(ret,v);
if(height[left]<height[right])left++;
else right--;
        }
return ret;
    }
}

5.有效三角形的个数

611. 有效三角形的个数 - 力扣(LeetCode)


题目描述

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。


示例 1:

输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是: 
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

示例 2:

输入: nums = [4,2,3,4]
输出: 4

解法:排序,对撞指针

算法思路

1.对数组进行排序,当较小的两边和大于第三边时,那么三边中中间大的数与最小边中间的数均可与中间大的数和最大边构成三角形

2.通过循环,每次固定最大边,left表示最小边,right表示中间的边

3.最大边从数组长度-1开始--(用i表示),left在每次循环里初始化为0,right在每次循环里初始化为i-1;ret记录符合条件的个数。

4.当nums[left]+nums[right]>nums[i]时,说明用left到right之间的数来充当left,nums[left]+nums[right]的结果都是大于nums[i],此时ret+=right-left,将right像左移动,再继续判断下一个区间

5.当nums[left]+nums[right]<nums[i]时,不符合条件,我们需要将left向右移动,使nums[left]+nums[right]的值更大,当left与right相遇时,说明i固定的值的所有可能结果找完了


JAVA算法代码:

class Solution {
    public int triangleNumber(int[] nums) {
        Arrays.sort(nums);
        int ret=0;
        for(int i=nums.length-1;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;
    }
}

6.查找总价值为目标值的两个商品

LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode)


题目描述

购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。


示例 1:

输入:price = [3, 9, 12, 15], target = 18
输出:[3,15] 或者 [15,3]

示例 2:

输入:price = [8, 21, 27, 34, 52, 66], target = 61
输出:[27,34] 或者 [34,27]

解法:对撞指针

算法思路

1.定义left和right两个指针

2.left初始化为1,right初始化为price.length-1

3.计算price[left]+price[right]的和与target做比较,大于righr--,小于left++,等于返回含有这两个元素的数组


JAVA算法代码

class Solution {
    public int[] twoSum(int[] price, int target) {
        int left=0;
        int right=price.length-1;
        while(left<right){
if(price[left]+price[right]>target)right--;
else if(price[left]+price[right]<target)left++;
else
   return new int[] {price[left], price[right]};
        }
 return new int[]{0};
    }
}

7.三数之和

15. 三数之和 - 力扣(LeetCode)


题目描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。


示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

解法:固定一个数,取相反值,对撞指针

算法思路

1.对数组进行排序

2.遍历数组,每次遍历,固定当前这个数,计算他的相反值,定义两个指针(left,right),left初始化为i+1,right初始化为nums.length-1,使用对撞指针,在i后面的区域内搜寻nums[left]+nums[right]==target的值,找到了就将i,left,right所指的值添加到链表里面

3.如果i所指的值是大于0的,那么就不用继续搜寻了,因为-nums[i]为负数,后面的nums[left]+nums[right]始终为正

4.去重操作,当我们找到一组数后,需要对left,right的值进行去重操作,当固定完一个数后,也需要对这个固定的数进行去重操作


JAVA算法代码

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

8.四数之和

18. 四数之和 - 力扣(LeetCode)


题目描述

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abc 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。


示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

解法:基于三数之和

算法思路

1.对数组进行排序

2.从0开始遍历数组,固定第一个数,从固定i+1位置数,遍历第二个数,用target减去第一个和第二个数得到aim,aim可能会超出int的范围,用long类型处理一下

3.用对撞指针left和right搜寻两数之和为aim的可能结果,每次找到,对left和right进行去重处理,第一个数和第二个数在自己循环一次过后也需要进行去重处理


JAVA算法代码

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>>ret=new ArrayList<>();
        Arrays.sort(nums);
        int n=nums.length;
        for(int i=0;i<n-3;){
for(int j=i+1;j<n-2;){
int left=j+1;
int right=n-1;
long aim=(long)target-nums[j]-nums[i];
while(left<right){

    long sum=nums[left]+nums[right];
if(sum<aim)left++;
else if(sum>aim)right--;
else{
ret.add(new ArrayList<>(Arrays.asList(nums[i],nums[j],nums[left],nums[right])));
left++;
right--;
while(left<right&&nums[left-1]==nums[left])left++;
while(left<right&&nums[right+1]==nums[right])right--;
}
}
j++;
while(j<n-2&&nums[j-1]==nums[j])j++;
}
i++;
while(i<n-3&&nums[i-1]==nums[i])i++;
        }
        return ret;
    }
}

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

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

相关文章

计算机网络期末复习-part1-概述

1、互联网的组成 互联网由两大块组成。 1、边沿部分&#xff1a;由所有连接在互联网上的主机组成&#xff0c;是用户直接使用的部分。 2、核心部分&#xff0c;由大量网络和路由器组成&#xff0c;为边缘部分提供服务。 2、数据传送阶段的三种交换方式的主要特点 1、电路交…

【Linux系统编程】——理解冯诺依曼体系结构

文章目录 冯诺依曼体系结构硬件当代计算机是性价比的产物冯诺依曼的存储冯诺依曼的数据流动步骤冯诺依曼结构总结 冯诺依曼体系结构硬件 下面是整个冯诺依曼体系结构 冯诺依曼结构&#xff08;Von Neumann Architecture&#xff09;是现代计算机的基本结构之一&#xff0c;由数…

微信创建小程序码 - 数量不受限制

获取小程序码&#xff1a;小程序码为圆图&#xff0c;且不受数量限制。 目录 文档 接口地址 请求方式 功能描述 注意事项 获取 scene 值 请求参数 返回参数 对接 请求方法 获取小程序码 调用获取小程序码 总结 文档 接口地址 https://api.weixin.qq.com/wxa/get…

JDK8 下载与安装

下载安装包 官网下载 官网 找到适合的版本: 网盘下载 网盘链接 提取码: 6666 下载得到的安装包: 安装步骤 双击安装包开始安装. 安装路径不要有中文或者特殊符号如空格等. 更改安装路径: 跳出一个页面, 安装公共 JRE: 安装完成: 安装目录: 安装的公共 JRE: JDK 里面的 JR…

笔记本电脑usb接口没反应怎么办?原因及解决方法

笔记本电脑的USB接口是我们日常使用中非常频繁的一个功能&#xff0c;无论是数据传输、充电还是外接设备&#xff0c;都离不开它。然而&#xff0c;当USB接口突然没有反应时&#xff0c;这无疑会给我们的工作和学习带来不小的困扰。下面&#xff0c;我们就来探讨一下笔记本USB接…

Axure设计之模拟地图人员移动轨迹

在产品原型设计时&#xff0c;为了更好的表达和呈现预期的效果&#xff0c;让客户或开发看一眼就能理解要实现的功能&#xff0c;往往需要在产品设计时尽量去接近现实&#xff0c;这就需要我们在使用Axure制作原型时应具有高度细节和逼真度的原型设计。原型设计不仅包含了产品的…

【配置查询】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

error=‘null‘], commandType=io.lettuce.core.RedisPublisher$SubscriptionCommand]

问题 查看java应用启动日志输出下面错误&#xff1a; errornull], commandTypeio.lettuce.core.RedisPublisher$SubscriptionCommand] Completing command LatencyMeteredCommand [typeINFO, outputStatusOutput [output# Server redis_version:4.0.14 redis_git_sha1:000…

Python 数据分析用库 获取数据(二)

Beautiful Soup Python的Beautiful Soup&#xff08;常被称为“美丽汤”&#xff09;是一个用于解析HTML和XML文档的第三方库&#xff0c;它在网页爬虫和数据提取领域具有广泛的应用。 作用 HTML/XML解析&#xff1a; Beautiful Soup能够解析HTML和XML文档&#xff0c;包括不…

915DEBUG-obsidianTemplater使用

Templater使用 tp函数不正常显示相应数据 模板使用方式不正确 <% tp.date.now("YYYY-MM-DD") %> 应该被放置在一个被Templater识别为模板的文件中&#xff0c;或者在你使用Templater的插入模板功能时输入。如果只是在一个普通的Markdown文件中直接输入这段代码…

美畅物联丨智能监控,高效运维:视频汇聚平台在储能领域的实践探索

在当今全球能源格局不断变化的大背景下&#xff0c;对清洁能源的需求正以惊人的速度增长。储能项目作为平衡能源供需、提升能源利用效率的关键环节&#xff0c;其规模和复杂度也在不断攀升。在储能项目的运营管理过程中&#xff0c;安全监控、设备运维以及数据管理等方面面临着…

华为NPU服务器昇腾Ascend 910B2部署通义千问Qwen2.5——基于mindie镜像一路试错版(三)

文章目录 前言纯模型推理启动服务后面干什么?这可咋整啊?愁死了!总结前言 这是咱这个系列的第三个文章了。 毕竟,这是我好几天摸索出的经验,能帮助各位在几个小时内领会,我觉得也算是我的功劳一件了。 所以,一是希望大家耐心看下去,耐心操作下去;而是恳请各位多多关…

【C++】—— set 与 multiset

【C】—— map 与 set 1 序列式容器和关联式容器2 set 系列的使用2.1 set 和 multiset 参考文档2.2 set 类的介绍2.3 set 的迭代器和构造2.4 set的增删查2.4.1 insert2.4.2 find 与 erase2.4.3 count 2.5 lower_bound 与 upper_bound2.6 multiset 与 set 的差异2.6.1 不再去重2…

`pnpm` 不是内部或外部命令,也不是可运行的程序或批处理文件(问题已解决,2024/12/3

主打一个有用 只需要加一个环境变量 直接安装NodeJS的情况使用NVM安装NodeJS的情况 本篇博客主要针对第二种情况&#xff0c;第一种也可参考做法&#xff0c;当然眨眼睛建议都换成第二种 默认情况下的解决方法&#xff1a;⭐⭐⭐ 先找到node的位置&#xff0c;默认文件夹名字…

JavaScript 键盘控制移动

如果你想通过 JavaScript 实现键盘控制对象&#xff08;比如一个方块&#xff09;的移动&#xff0c;下面是一个简单的示例&#xff0c;展示如何监听键盘事件并根据按下的键来移动一个元素。 HTML 和 CSS&#xff1a; <!DOCTYPE html> <html lang"en">…

【串口助手开发】visual studio 使用C#开发串口助手,生成在其他电脑上可执行文件,可运行的程序

1、改成Release&#xff0c;生成解决方案 串口助手调试成功后&#xff0c;将Debug改为Release&#xff0c;点击生成解决方案 2、运行exe文件 生成解决方案后&#xff0c;在bin文件夹下&#xff0c; Release文件夹下&#xff0c;生成相关文件 复制一整个Release文件夹&#xf…

通过HTML Canvas 在图片上绘制文字

目录 前言 一、HTML Canvas 简介 二、准备工作 三、绘制图片 四、绘制文字 五、完整代码 效果演示&#xff1a; 前言 HTML canvas 为我们提供了无限的创意可能性。今天&#xff0c;我们就来探索一下如何通过 HTML canvas 将图片和文字绘制到图片上&#xff0c;创造出独特…

Android ION Buffer

目录 背景介绍 ION内存管理机制主要解决了以下几个关键问题&#xff1a; ION的实际应用场景 背景介绍 ION是Android 4.0 ICS(Ice Cream Sandwich)引入的一个通用内存管理器&#xff0c;用于解决不同Android设备之间内存管理接口碎片化的问题。至少有三个或者更多类似PMEMM接…

qt程序开发环境部署

安装 sudo apt install qt5-default sudo apt install qtcreator sudo apt install g直接安装&#xff0c;linux的源里一般都有&#xff0c;如果没有&#xff0c;那就辛苦找下源了。。。 设置kit 然后启动qtcreator&#xff0c;构建套件&#xff0c;选择合适的编译器&#…

聊聊JVM G1(Garbage First)垃圾收集器

CMS的垃圾回收机制&#xff0c;为什么分为四步https://blog.csdn.net/genffe880915/article/details/144205658说完CMS垃圾回收器&#xff0c;必定要说到目前一般应用项目中都推荐的G1。G1在JDK1.7 update4时引入&#xff0c;在JDK9时取代CMS成为默认的垃圾收集器。它是HotSpot…