【算法day1】数组:双指针算法

题目引用

这里以

1、LeetCode704.二分查找

2、LeetCode27.移除元素

3、LeetCode977.有序数组的平方

这三道题举例来说明数组中双指针的妙用。

1、二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

首先我们来理解一下题意

我们需要在一段连续递增的数组当中找到 ==target 元素,并在函数结尾返回它。

暴力的解法是直接把数组遍历一遍,一一比对,找到后返回。当然时间复杂度会是 O(N) 级别的。

那么有没有更简便的写法呢?

当然有,那就是我们今天要见识到的 双指针算法

首先我们初始化两个指针,一个指向数组的头left,另一个指向数组的尾right。并且维护一个 mid 指针,使其始终处于 [left,right] 范围内,比较数组 mid 位置与target 的数值大小。如果 mid 位置的数值比target大,那么将right移动到mid 位置,再次更新mid 位置。如果 mid 位置的数值比target 小,那么将left 移动到mid 位置,再次更新mid 位置。如此循环直到找到 ==target 值的位置或者 left>right 循环结束。

注意:由于区间的个人喜好不同,一般有左闭右开 写法和左闭右闭 两种写法。

左闭右开写法:

cpp 复制代码
int search(vector<int>& nums, int target) {
        int left=0,right=nums.size();
        while(left<right){
            int mid=(left+right)>>1;
            if(target>nums[mid]){
                left=mid+1;
            }else if(target<nums[mid]){
                right=mid;
            }else{
                return mid;
            }
        }
        return -1;
    }

左闭右闭写法:

cpp 复制代码
int search(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1;
        while(left<=right){
            int mid=(left+right)>>1;
            if(target>nums[mid]){
                left=mid+1;
            }else if(target<nums[mid]){
                right=mid-1;
            }else{
                return mid;
            }
        }
        return -1;
    }

那么这题就被完美地解决了~

2、移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。

返回 k。

我们来理解一下题意:

给了我们一个存储着随机元素且随机长度的数组,让我们来移除 ==val 的元素,这道题当然可以遍历一遍数组,将数组中 ==val 的元素全部覆盖掉,但是这样是很容易丢失数据位置进而引发结果错误的。那么应该怎么写才能快速而优雅地AC它呢?当然还是双指针。

我们定义两个指针,一个快指针fast,一个慢指针slow。我们让fast指针先走,边走边判断数组中的元素是否 ==val 。如果等于,我们继续往下走(是不是很奇怪?别急,慢慢看),如果 !=val ,我们让fast位置的值和slow位置的值交换,并且 slow++ 。当fast走到数组末尾的时候,返回slow。

为什么?

为什么slow位置就能代表 !=val 的所有元素的数目呢?

我来画个图给大家看看






所以返回slow就会是被移除后的元素数量。

附上代码

cpp 复制代码
int removeElement(vector<int>& nums, int val) {
        int slow=0;
        for(int fast=0;fast<nums.size();fast++){
            if(nums[fast]!=val) nums[slow++]=nums[fast];
        }
        return slow;
    }

这题也就完美的完成啦~

3、有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

这题我们也分析一下下~

首先用暴力算完再排序也是可以的~但我们是手艺人,不能题题都暴力。

这题也是给我们一个非递减数组,也就是要么增要么等。那么还是使用双指针来解吧。定义一个头指针i,尾指针j,遍历数组,比较 nums[i] , nums[j] 平方后的大小, i 位置的平方比较大就交换,反之则将 平方后的数 放回数组对应位置继续循环。

直接上代码

cpp 复制代码
vector<int> sortedSquares(vector<int>& nums) {
       int n = nums.size();
       vector<int> ans(n);
       int i = 0, j = n - 1;
       for (int p = n - 1; p >= 0; p--) {
           int x = nums[i], y = nums[j];
           if (-x > y) {
               ans[p] = x * x;
               i++;
           } else {
               ans[p] = y * y;
               j--;
           }
       }
       return ans;
   }

总结

双指针算法既简便又能快速解决问题,如果我们遇到数组相关的问题可以积极考虑它。

相关推荐
Mrlxl.cn1 小时前
计算机网络——网络层
c语言·数据结构·计算机网络·考研
d111111111d2 小时前
STM32-UART封装问题解析
笔记·stm32·单片机·嵌入式硬件·学习·算法
寒秋花开曾相惜2 小时前
(学习笔记)4.2 逻辑设计和硬件控制语言HCL(4.2.1 逻辑门&4.2.2 组合电路和HCL布尔表达式)
linux·网络·数据结构·笔记·学习·fpga开发
Jiangxl~4 小时前
IP数据云如何为不同行业提供精准IP查询与风险防控解决方案?
网络·网络协议·tcp/ip·算法·ai·ip·安全架构
李伟_Li慢慢4 小时前
wolfram详解山峦算法
前端·算法
counting money4 小时前
prim算法最小生成树(java)
算法
澈2075 小时前
C++面向对象:类与对象核心解析
c++·算法
用户690673881925 小时前
基于无人机的单目测距系统,平均误差仅2.12%
算法
dinl_vin5 小时前
LangChain 系列·(四):RAG 基础——给大模型装上“外脑“
人工智能·算法·langchain
码完就睡5 小时前
数据结构——哈希表原理与C语言实现总结
数据结构·散列表