优选算法——双指针1

双指针

常⻅的双指针有两种形式,⼀种是对撞指针,⼀种是左右指针。

对撞指针:⼀般⽤于顺序结构中,也称左右指针。

  1. 对撞指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼 近。
  2. 对撞指针的终⽌条件⼀般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循 环),也就是:
  • left == right (两个指针指向同⼀个位置)
  • left > right (两个指针错开)

快慢指针:⼜称为⻳兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列 结构上移动。

 这种⽅法对于处理环形链表或数组⾮常有⽤。

其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使⽤快 慢指针的思想。

快慢指针的实现⽅式有很多种,最常⽤的⼀种就是: 

  • 在⼀次循环中,每次让慢的指针向后移动⼀位,⽽快的指针往后移动两位,实现⼀快⼀慢。

注:双指针只是一种思想,我们不一定真的要定义指针来实现双指针,我们可以使用特定的数值来表示指针,比如说数组的下标,某元素的值

第一题——移动零

「数组分两块」是⾮常常⻅的⼀种题型,主要就是根据⼀种划分⽅式,将数组的内容分成左右两部 分。这种类型的题,⼀般就是使⽤「双指针」来解决。

题目来源. - 力扣(LeetCode) 

思路(快排的思想:数组划分区间-数组分两块)

在本题中,我们可以⽤⼀个 cur 指针来扫描整个数组,另⼀个 dest 指针⽤来记录⾮零数序列的最后一个位置。根据 cur 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。

在 cur 遍历期间,使 [0, dest] 的元素全部都是⾮零元素, [dest + 1, cur - 1] 的 元素全是零。

那我们要怎么做呢?很简单

我们直接看例子

我们发现1——5步均符合下面这个区间的要求

 代码

void swap(int*a,int*b)
{
    int tmp=*a;
    *a=*b;
    *b=tmp;
}
void moveZeroes(int* nums, int numsSize) {
         for(int cur = 0, dest = -1; cur < numsSize; cur++)
                if(nums[cur]) // 处理⾮零元素
                 swap(&nums[++dest], &nums[cur]);
    
}

第二题——复写零

题目来源:. - 力扣(LeetCode)

我们先审题,它这个题目到底要我们干什么,我们看下面这个图就明白了

假设上面这个是传入的数组,下面这个就是完成复写零的数组

思路:

来看看另外开辟一个数组的做法 

 把异地操作模拟成就地操作

我们先看看从前往后的双指针法行不行

显然不行

我们再看看从后往前的方式 

完全可以嘿!那我们怎么找最后一个被复写的数呢?我们还是用双指针去找

 

 但是,这个算法还不健全,它在下面这个情况会发生越界访问

代码:

void duplicateZeros(int* arr, int arrSize) {

    // 1. 先找到最后⼀个数
    int cur = 0, dest = -1, n = arrSize;
    while (cur < n)
    {
        if (arr[cur]) 
            dest++;
        else 
            dest += 2;
        if (dest >= n - 1)
            break;
        cur++;
    }
    
    // 2. 处理⼀下边界情况
    if (dest == n)
    {
        arr[n - 1] = 0;
        cur--; dest -= 2;
    }
    
    // 3. 从后向前完成复写操作
    while (cur >= 0)
    {
        if (arr[cur]) 
            arr[dest--] = arr[cur--];
        else
        {
            arr[dest--] = 0;
            arr[dest--] = 0;
            cur--;
        }
    }
}

第三题——快乐数

题目来源:. - 力扣(LeetCode)

 思路

先审题

要么变到一,要么循环,我们直接把它抽象成第一种情况为最后是形成所有元素都是一的环,第二种情况是所有元素都不是1的环

这不就是判断链表里是不是有环的问题吗?

 有人就想了,我们怎么定义指针?

这里我们就要注意了,双指针只是一种思想,我们不一定真的要定义指针来实现双指针,我们可以使用特定的数值来表示指针,比如说数组的下标,但是在这里我们可以用数字来表示指针

我们先看slow指针

fast指针也是同理

我们就抽象成下面这个 

 

有人就想,万一它一直不成环,一直无限循环下去怎么办?

 但是,这是不可能的

我们来证明一下

我们直接取10个9,这是超过题目范围的,而且这个值产生拆分后的数一定是超过题目的 

 所以假设题目的数的范围和这个一样大,那它的取值范围是【1,810】,也就是说在这个数值范围产生的拆分后的数值一定是在【1,810】的,也就是说它最多循环810次,到811次之后一定会产生重复的值的,所以一直循环的情况不存在

根据上述的题⽬分析,我们可以知道,当重复执⾏ x 的时候,数据会陷⼊到⼀个「循环」之中。 ⽽「快慢指针」有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的,也就是说他们总会 相遇在⼀个位置上。如果相遇位置的值是 1 ,那么这个数⼀定是快乐数;如果相遇位置不是 1 的话,那么就不是快乐数。

补充知识:如何求⼀个数n每个位置上的数字的平⽅和。

a. 把数 n 每⼀位的数提取出来: 循环迭代下⾯步骤:

  • int t = n % 10 提取个位;
  • n /= 10 ⼲掉个位; 直到 n 的值变为 0 ;

b. 提取每⼀位的时候,⽤⼀个变量  tmp 记录这⼀位的平⽅与之前提取位数的平⽅和

tmp = tmp + t * t

代码

int bitSum(int n) // 返回n 这个数每⼀位上的平⽅和
{ 
        int sum = 0;
        while(n)
        {
            int t = n % 10;
            sum += t * t;
            n /= 10;
        }
        return sum;
    
}

bool isHappy(int n)     
{
        int slow = n, fast = bitSum(n);
        while(slow != fast)
        {
            slow = bitSum(slow);
            fast = bitSum(bitSum(fast));
        }
        return slow == 1;
}

第四题——盛最多水的容器

题目来源:盛最多水的容器 

思路 

我们可以使用暴力枚举

但是这个会超时 

我们先拿一个数组来试试,取边界为墙,我们知道啊,容器的容积是取决于容器最矮的那一端,这里也是类似的,这里容器的容量取决于最小的——4,我们就想把4变成大点的数容器的容积不就上去了吗?于是我们向内枚举,情况如下

我们发现,我们取6为墙的时候,右边的数向左枚举,没有一个容器的容积比原来的大的

 我们再看看一个例子

算法思路: 设两个指针 left , right 分别指向容器的左右两个端点,此时容器的容积:

容器的左边界为 height[left] ,右边界为 height[right] 。

为了⽅便叙述,我们假设「左边边界」⼩于「右边边界」。

如果此时我们固定⼀个边界,改变另⼀个边界,⽔的容积会有如下变化形式:

  •  容器的宽度⼀定变⼩。
  •  由于左边界较⼩,决定了⽔的⾼度。如果改变左边界,新的⽔⾯⾼度不确定,但是⼀定不会超 过右边的柱⼦⾼度,因此容器的容积可能会增⼤。
  • 如果改变右边界,⽆论右边界移动到哪⾥,新的⽔⾯的⾼度⼀定不会超过左边界,也就是不会 超过现在的⽔⾯⾼度,但是由于容器的宽度减⼩,因此容器的容积⼀定会变⼩的。

由此可⻅,左边界和其余边界的组合情况都可以舍去。所以我们可以 left++ 跳过这个边界,继 续去判断下⼀个左右边界。 当我们不断重复上述过程,每次都可以舍去⼤量不必要的枚举过程,直到 遇。期间产⽣的所有的容积⾥⾯的最⼤值,就是最终答案。 

class Solution {
public:

int maxArea(vector<int>& height)
{
    int left = 0, right = height.size() - 1, ret = 0;
    while (left < right)
    {
        int v = min(height[left], height[right]) * (right - left);
        ret = max(ret, v);
        // 移动指针
            if (height[left] < height[right]) 
                left++;
            else 
                right--;
    }
    return ret;
}
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

品鉴中的品鉴笔记:如何记录和分享自己的品鉴心得

品鉴云仓酒庄雷盛红酒的过程&#xff0c;不仅是品尝美酒&#xff0c;更是一次与葡萄酒深度对话的旅程。为了更好地记录和分享自己的品鉴心得&#xff0c;养成写品鉴笔记的习惯是十分必要的。 首先&#xff0c;选择一个适合的记录工具。可以是传统的笔记本&#xff0c;也可以是…

linux性能监控之free

free&#xff1a;linux系统自带命令&#xff0c;显示内存状态&#xff0c;命令查询来源于/proc/meminfo 文件 [rootk8s-master ~]# free --helpUsage:free [options]Options:-b, --bytes show output in bytes-k, --kilo show output in kilobytes-m, --mega…

一文掌握gRPC

文章目录 1. gRPC简介2. Http2.0协议3. 序列化-Protobuf4. gRPC开发实战环境搭建5. gRPC的四种通信方式&#xff08;重点&#xff09;6. gRPC的代理方式7. SprintBoot整合gRPC 1. gRPC简介 gRPC是由google开源的高性能的RPC框架。它是由google的Stubby这样一个内部的RPC框架演…

HCIA和HCIP区别大吗?小白请看这

华为认证以其专业性和实用性受到了业界的广泛认可。 HCIA、HCIP、HCIP这三个级别&#xff0c;你会选哪个&#xff1f;IE含金量不用多说&#xff0c;IA还是IP&#xff0c;你会纠结吗。 但面对这两个级别的认证&#xff0c;初学者或者“小白”们可能会感到困惑&#xff1a;两者…

智能体Agent笔记

智能体的定义&#xff1a; 1. 可以感受环境中的动态条件 2. 能采取动作影响环境 3. 能运用推理能力理解信息&#xff0c;解决问题&#xff0c;产生推断&#xff0c;决定动作。 我个人觉得智能体是个饼&#xff0c;最核心的问题是&#xff0c;你如何解决大模型的幻觉问题&…

Kafka官方文档中文版+Kafka面试题详解!

你了解kafka吗&#xff1f;目前它在一线互联网公司以迅雷不及掩耳之势得到了广泛的应用。但究竟是什么呢&#xff1f;Kafka最初于2011年在LinkedIn开发&#xff0c;自那时起经历了很多改进。如今它是一个完整的平台&#xff0c;允许您冗余地存储荒谬的数据量&#xff0c;拥有一…

AD原理图设置:如何在编译工程时,报未连接线或引脚错误

如下图&#xff0c;AD默认在编译原理图时&#xff0c;如果出现未连接的引脚或线时&#xff0c;并不会报相关的错误&#xff0c;这样做其实很危险 所以&#xff0c;我们应该让它提示错误 具体配置方法&#xff1a; 1、找到工程选项 2、切换到第二个选项“Connection Matrix”&a…

RedisTemplate操作Redis详解之连接Redis及自定义序列化

连接到Redis 使用Redis和Spring时的首要任务之一是通过IoC容器连接到Redis。为此&#xff0c;需要java连接器&#xff08;或绑定&#xff09;。无论选择哪种库&#xff0c;你都只需要使用一组Spring Data Redis API&#xff08;在所有连接器中行为一致&#xff09;&#xff1a;…

游戏中的设计模式一

游戏开发是一个快速迭代的过程&#xff0c;代码复杂度也很高&#xff0c;借助于设计模式&#xff0c;可以帮助我们降低复杂度&#xff0c;降低系统间的耦合&#xff0c;从而高效高质的做出交付。 最近读了这本书&#xff1a;《游戏编程模式》[1]&#xff0c;很受启发&#xff…

探索Playwright:Python下的Web自动化测试革命

在如今这个互联网技术迅速发展的时代&#xff0c;web应用的质量直接关系着企业的声誉和用户的体验。因此&#xff0c;自动化测试成为了保障软件质量的重要手段之一。今天&#xff0c;我将带大家详细了解一款在测试领域大放异彩的神器——Playwright&#xff0c;并通过Python语言…

【搬砖实战】2024年了,还有人不会搭建内网穿透吗?

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本文讲解动手自己搭建内网穿透&#xff0c;期待与你一同探索、学习、进步&#xff0c;一起卷起来叭&#xff01; 目录 一、前言内网穿透是什么&#xff1f;frp介绍&#xff1a…

Golang SDK安装

windows环境安装 1.链接: 下载地址 2.安装SDK 检查环境变量&#xff1a; 3.开启go modules,命令行执行一下命令&#xff1a; go env -w GO111MODULEon4.设置国内代理&#xff0c;命令行执行一下命令&#xff1a; go env -w GOPROXYhttps://proxy.golang.com.cn,https:/…

【Linux】进程信号(2万字)

目录 前言 一、生活角度的信号 1.1、我们来见一见信号&#xff1a; 1.2、模拟一下 kill 指令 二、信号的处理 三、产生信号的5种方法 3.1、kill命令 3.2、键盘可以产生信号 3.3、3种系统调用 3.4、软件条件 3.5、异常 四、比较 core 和 Term 五、键盘信号产生 六…

AI绘画如何变现?stablediffusion小白上手指南:2个工具+4个渠道

公司一计算机大佬&#xff0c;用AI画画一个月搞钱1w&#xff0c;画着画着都快超过本职工资了。费了点小心思整理出这篇文章&#xff0c;把搜刮来的一手经验全盘托出&#xff0c;觉得有用的友友记得点赞收藏哦&#xff01; 我有个朋友学设计的&#xff0c;今年找了大半年工作&a…

【轮转数组】力扣python

1.python切片 这里nums[:]代表列表 class Solution:def rotate(self, nums: List[int], k: int) -> None:nlen(nums)nums[:]nums[-k%n:]nums[:-k%n] 2.边pop边push 0代表插入的位置 class Solution:def rotate(self, nums: List[int], k: int) -> None:nlen(nums)fo…

OpenAi 免费GPT-4o来袭,音频视觉文本实现「大一统」

今天凌晨&#xff0c;即北京时间5月14日1点整&#xff0c;OpenAI 召开了首场春季发布会&#xff0c;CTO Mira Murati 在台上和团队用短短不到30分钟的时间&#xff0c;揭开了最新旗舰模型 GPT-4o 的神秘面纱&#xff0c;以及基于 GPT-4o 的 ChatGPT&#xff0c;均为免费使用。 …

试试这四个AI论文工具和降重技术,低成本高回报

在科研领域&#xff0c;AI写作工具如同新一代的科研利器&#xff0c;它们能够极大提高文献查阅、思路整理和表达优化的效率&#xff0c;本质上促进了科研工作的进步。AI写作工具不仅快速获取并整理海量信息&#xff0c;还帮助我们精确提炼中心思想&#xff0c;显著提升论文写作…

智能终端RK3568主板在智慧公交条形屏项目的应用,支持鸿蒙,支持全国产化

基于AIoT-3568A的智慧公交条形屏&#xff0c;可支持公交线路动态展示&#xff0c;语音到站提醒&#xff0c;减少过乘、漏乘的情况&#xff0c;有效提高了公交服务效率和质量&#xff0c;为乘客提供了更舒适、更安全和更方便的出行体验&#xff0c;为城市的发展增添了新的活力。…

WS2812B-2020 智能控制LED集成光源芯片IC

一般说明 WS2812B-2020是一款智能控制LED光源&#xff0c;它的外部采用了最新的模压封装技术&#xff0c;控制电路和RGB芯片集成在一个2020组件中。其内部包括智能数字端口数据锁存器和信号整形放大驱动电路。还包括一个精密的内部振荡器和一个电压可编程恒流控制部分&…

从零开始学习Linux(8)----自定义shell

shell从用户读入字符串“ls”&#xff0c;shell建立一个新的进程&#xff0c;然后在那个进程中运行ls程序并等待那个进程结束。然后shell读取新的一行输入&#xff0c;建立一个新的进程&#xff0c;在这个进程中运行程序&#xff0c;并等待这个进程结束。所以要写一个shell&…