【算法】数组之二分查找移除元素

news2025/7/22 5:30:50

目录

1、数组理论基础

2、二分查找

 2.1 区间左闭右闭写法

2.2 区间左闭右开写法 

 3、移除元素

3.1  暴力解法

3.2 双指针(快慢指针)法


1、数组理论基础

参考以前的博客:http://t.csdn.cn/HAVSF

2、二分查找

力扣https://leetcode.cn/problems/binary-search/

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

【参考代码】 

int search(int* nums, int numsSize, int target){
     int left = 0;
     int right = numsSize - 1;
     while(left<=right)
     {
         int mid = left+(right-left)/2;
         if(nums[mid]>target)
         {
            right = mid-1;
         }
         else if(nums[mid]<target)
         {
            left = mid+1;
         }
         else
         {
            return mid;
         }
     }
     return -1;
}

首先关于这个二分查找法,主要有两个易错点,一个是while循环条件里面的符号究竟是小于等于还是小于。另一个是if—else if—else里面的判断体究竟需不需要进行加一减一的操作

要解决这个问题还是从问题本身出发,那就是没有搞清楚区间的定义,而定义过的区间就是固定的,即“不变量”。每一次循环里面的处理都需要根据区间来选择,这也是为什么有时候有些题加一减一似乎对其没什么影响,但有时候又必须加一或者减一。

下面给出二分法写法的两个版本:

 2.1 区间左闭右闭写法

int search(int* nums, int numsSize, int target){
     int left = 0;
     int right = numsSize - 1;
     while(left<=right)
     {
         int mid = left+(right-left)/2;
         //int mid = (left+right)/2;
         //int mid = left+(right-left)>>1;
         if(nums[mid]>target)
         {
            right = mid-1;
         }
         else if(nums[mid]<target)
         {
            left = mid+1;
         }
         else
         {
            return mid;
         }
     }
     return -1;
}

在这种情况下,target是定义在[left,right]上的,此时left=right是有意义的,注意这里跟数学里面的区间定义不同,因为有意义,所以此时while(left<=right),如果你少写=,会有值被你漏算。除此之外,你还需要注意一下if判断体里面是否需要加一或减一,如果nums[mid]>target,说明当前的nums[mid]一定不是target,所以更新后的搜索右下标范围为mid-1。

2.2 区间左闭右开写法 

int search(int* nums, int numsSize, int target){
    int left = 0;
    int right = numsSize;
    while(left<right)
    {
        int mid = left+(right-left)/2;
        if(nums[mid]>target)
        {
            right = mid;
        }
        else if(nums[mid]<target)
        {
            left = mid+1;
        }
        else
        {
            return mid;
        }
    }
    return -1;
}

在这种情况下,target是定义在[left,right)上的,此时left=right是没有意义的,因为没有意义,所以此时while(left<right)。除此之外,你还需要注意一下if判断体里面是否需要加一或减一,如果nums[mid]>target,说明当前的nums[mid]一定不是target,而右区间本就是开区间,所以更新后的搜索右下标范围为mid。但nums[mid]<target,而左区间是闭的,所以坐下标需要进行加一。

【相关题目训练】

1.力扣https://leetcode.cn/problems/search-insert-position/
2.力扣https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/3.力扣https://leetcode.cn/problems/sqrtx/4.力扣https://leetcode.cn/problems/valid-perfect-square/

 3、移除元素

力扣https://leetcode.cn/problems/remove-element/

【题目】给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

【思路】要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。

以下给出两个方法: 

3.1  暴力解法

//两个for循环,一个for遍历整个数组元素,另一个更新数组元素
int removeElement(int* nums, int numsSize, int val){
    for(int i=0;i<numsSize;i++)
    {
        if(nums[i]==val)  //出现目标元素,就将数组整体向前移一步。
        {
            for(int j=i+1;j<numsSize;j++)
            {
                nums[j-1] = nums[j];
            }
            i--;  //因为下标i后面的都向前移了一位,所以i也需要向前移一位。
            numsSize--;  //此时数组长度-1 
        }
    }
    return numsSize;
}

在本代码中:

  • 时间复杂度:O(n^{2})
  • 空间复杂度:O(1)

3.2 双指针(快慢指针)法

通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针:

  • 寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 指向更新后新数组下标的位置
int removeElement(int* nums, int numsSize, int val){
    
    int slow = 0;
    for(int fast =0;fast<numsSize;fast++)
    {
        if(val!=nums[fast])
        {
            nums[slow++]=nums[fast];
        }
    }
    return slow;
}

 在本代码中:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

 【本题小结】显然法二明显优于法一,双指针法在数组和链表的操作中是很常见的,很多数组链表OJ题都可以使用双指针法解决。

【相关题目训练】 

力扣https://leetcode.cn/problems/remove-duplicates-from-sorted-array/

力扣https://leetcode.cn/problems/move-zeroes/

力扣https://leetcode.cn/problems/backspace-string-compare/

力扣https://leetcode.cn/problems/squares-of-a-sorted-array/

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

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

相关文章

Denodo通过重要任命新增执行团队成员:Daniel Lender担任首席财务官,Stephen Welles担任首席法务官

韩国Pulmuone选择Aera Decision Cloud™来提升服务&#xff0c;降低成本&#xff0c;并支持可持续性 决策智能化公司Aera Technology今日宣布与韩国领先的生鲜食品公司、全球排名居首的豆腐生产商Pulmuone Co. Ltd.合作&#xff0c;帮助这家全球领军企业实现供应链决策智能化。…

数据结构之栈和队列

目录 1.栈的概念2、栈的实现 1、队列的概念2、队列的实现 今天介绍的是栈和队列。 先说栈吧。 1.栈的概念 栈也是线性表的一种&#xff0c;不过他较为特殊。他只能在一边进行数据的出入。也就是说晚进的数据先出去。进行数据进出的一端叫做栈顶&#xff0c;另一端叫做栈底…

从ReentrantReadWriteLock开始的独占锁与共享锁的源码分析

FBI WARNING&#xff08;bushi&#xff09; 当涉及sync调用时&#xff0c;并不会分析尝试获取和释放之后的后继逻辑&#xff0c;因为这个逻辑是由AQS类实现的。请看姊妹篇之并发入门组件AQS源码解析。 开始的开始是一个demo 以下的代码&#xff0c;会将独占锁持有5分钟&…

【LSTM实战】股票走势预测全流程实战(stock predict)

任务&#xff1a;利用LSTM模型预测2017年的股票中High的走势&#xff0c;并与真实的数据进行比对。数据&#xff1a;https://www.kaggle.com/datasets/princeteng/stock-predict 一、import packages|导入第三方库 import pandas as pd import matplotlib.pyplot as plt impo…

利用ESP32实现蓝牙通信的方法

​大家好&#xff0c;我是ST! 上次给大家分享了如何使用ESP32实现UDP通信&#xff0c;今天跟大家聊聊如何使用ESP32实现蓝牙通信。 目录 一、蓝牙简介 二、miropython有关蓝牙的实现方法 三、我的实验代码 四、手机调试APP 一、蓝牙简介 蓝牙是一种无线通讯技术&#xff…

Linux篇【5】:Linux 进程概念(三)

目录 四、进程状态 4.1、各个操作系统下的进程状态&#xff1a; 4.1.1、进程的运行态&#xff1a; 4.1.2、进程的终止态(退出态)&#xff1a; 4.1.3、进程的阻塞态&#xff1a; 4.1.4、进程的挂起态&#xff1a; 4.2、Linux 操作系统下的进程状态&#xff1a; 四、进…

30、Java高级特性——Java API、枚举、包装类、装箱和拆箱

目录 课前先导&#xff1a; 一、Java API 1、API 2、Java API 3、Java API常用包 二、枚举类型 1、枚举 2、枚举类 3、代码演示 3.1 创建枚举类 3.2 创建测试类 4、MyEclipse创建枚举类的快捷方式 三、包装类 1、八大基本数据类型包装类 2、包装类中的构造方…

Java并发编程之可见性分析 volatile

可见性 对于什么是可见性&#xff0c;比较官方的解释就是&#xff1a;一个线程对共享变量的修改&#xff0c;另一个线程能够立刻看到。 说的直白些&#xff0c;就是两个线程共享一个变量&#xff0c;无论哪一个线程修改了这个变量&#xff0c;则另外的一个线程都能够看到上一…

电脑可以通过蓝牙发送文件吗?电脑蓝牙怎么发送文件

蓝牙&#xff08;bluetooth&#xff09;是一种支持设备短距离通信的无线电技术。能在包括移动电话、PDA、无线耳机、笔记本电脑、相关外设等众多设备之间进行无线信息交换。蓝牙技术让数据传输变得更加迅速高效&#xff0c;为无线通信拓宽道路。随着蓝牙技术的发展&#xff0c;…

甘露糖-聚乙二醇-羧酸|mannose-PEG-COOH|羧酸-PEG-甘露糖

甘露糖-聚乙二醇-羧酸|mannose-PEG-COOH|羧酸-PEG-甘露糖 首先合成了二,三分支的甘露糖簇分子.甘露糖经烯丙 苷化,乙酰基保护后,将其烯丙基的双键氧化得到带有羧基连接臂的甘露糖衍生物,然后再分别与1,6-己二胺和三(2-氨乙基)胺进行缩合反应,后脱掉保 护基,得到二分枝甘露糖簇…

Azide-PEG-Thiol,N3-PEG-SH,叠氮-聚乙二醇-巯基可用来制备金纳米颗粒

1、名称 英文&#xff1a;Azide-PEG-Thiol&#xff0c;N3-PEG-SH 中文&#xff1a;叠氮-聚乙二醇-巯基 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a;Azide PEG Thiol PEG 4、分子量&#xff1a;可定制&#xff0c;5k N3-PEG-SH、20k 叠氮-聚乙二醇-巯基、10k N3-PE…

嵌入式分享合集105

一、智能灯光控制系统&#xff08;基于stm32&#xff09; 带你走进物联网的世界说一个整天方案哦 这次是基于stm32的 当然你可以用esp “智能光照灯”使用STM32作为系统的MCU&#xff0c;由于单片机IO口驱动电流过小&#xff0c;搭配三极管放大电流&#xff0c;从而满足光照强…

全网监控 nginx 部署 zabbix6.0

Zabbix监控 文章目录Zabbix监控一、zabbix6.0部署1、部署zabbix 6.0版本&#xff08;nginxphpzabbix&#xff09;1、nginx配置2、php配置3、mariadb配置二、zabbix配置1、zabbix配置 &#xff08;6.0&#xff09;1、源码安装2、zabbix rpm2、zabbix(5.0安装) -- 补充3、故障汇总…

【Linux】翻山越岭——进程地址空间

文章目录一、是什么写时拷贝二、为什么三、怎么做区域划分和调整一、是什么 回顾我们学习C/C时的地址空间&#xff1a; 有了这个基本框架&#xff0c;我们对于语言的学习更加易于理解&#xff0c;但是地址空间究竟是什么❓我们对其并不了解&#xff0c;是不是内存呢&#xff1…

【创建微服务】创建微服务并使用人人开源代码生成器生成基本代码

创建项目微服务 —— 添加模块 添加依赖 使用 人人开源代码生成器 快速生成 crud 代码 —— https://gitee.com/renrenio 下载导入人人开源项目后&#xff0c;修改 application.yml 文件下的数据库连接配置&#xff1a; 2. 修改 generator.properties 配置文件下的 主路径、包…

CC1101RGPR射频收发器 Low-Power Sub-1GHz 射频收发器

CC1101RGPR射频收发器 Low-Power Sub-1GHz 射频收发器 CC1101RGPR是一种低成本的 sub-1 GHz 收发器专为超低功耗无线应用而设计。该电路主要用于ISM&#xff08;工业、科学和医疗&#xff09;和SRD&#xff08;短程设备&#xff09;频段315、433、868 和 915 MHz&#xff0c;但…

【891. 子序列宽度之和】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。 给你一个整数数组 nums &#xff0c;返回 nums 的所有非空 子序列 的 宽度之和 。由于答案可能非常大&#xff0c;请返回对 109 7 取余 …

UNIAPP实战项目笔记40 设置和地址的页面布局

UNIAPP实战项目笔记40 设置和地址的页面布局 my-config.vue 设置页面布局 具体图片自己替换哈&#xff0c;随便找了个图片的做示例 代码 my-config.vue 页面部分 <template><view class"my-config"><view class"config-item" tap"go…

精益项目管理的流程

我们生活在一个企业家的世界&#xff0c;您可能有许多自己的想法等待实现&#xff0c;但想法在现实中实现是昂贵的。问题是您如何才能获得最大的收益&#xff1f;CEO和管理者如何在追逐梦想和实现目标的同时节省资金&#xff1f;了解初创公司如何进行精益项目管理&#xff0c;它…

第一个汇编程序

第一个汇编程序 文章目录第一个汇编程序1.汇编模拟程序&#xff1a;DOSBox使用2.汇编程序从写出到执行的过程3.程序执行过程跟踪1.汇编模拟程序&#xff1a;DOSBox使用 BOSBox软件常用基本语法&#xff1a; mount c: d:\masn ;挂载磁盘,挂载后用c:切换为C盘才能用debug等工具…