零基础刷代码随想录【Day1】|| 二分查找,移除元素

news2024/11/15 23:57:14

我的个人主页:☆光之梦☆的博客_CSDN博客-C语言基础语法(超详细)领域博主

欢迎各位 👍点赞 ⭐收藏 📝评论

我的专栏:C语言基础语法(超详细)_☆光之梦☆的博客-CSDN博客(这个专栏里的平均文章质量分是95噢,基本全都是高质量文章,本博主将会长期更新c语言的语法知识,初学c语言的朋友们,可以收藏订阅一下,收藏绝对不亏噢)

目录

day1

数组理论基础

二分查找(leetcode704)

题目描述

二分查找易错点

解题思路&代码

方法1:左闭右闭

方法2:左闭右开

移除元素(leetcode27)

题目描述

解题思路&代码

方法1:暴力解法

方法2:双指针法


day1

数组理论基础

数组是存放在连续内存空间上的相同类型数据的集合

数组是通过下标索引的方式获取到下标下对应的数据

需要注意的是

  • 数组下标都是从0开始的。
  • 数组内存空间的地址是连续的

正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增加元素的时候,就难免要移动其他元素的地址。

数组的元素是不能删的,只能覆盖

内存地址,我就简单介绍一下, 0x7ffee4065820 与 0x7ffee4065824 差了一个4,就是4个字节,因为这是一个int型的数组,所以两个相邻数组元素地址差4个字节。

0x7ffee4065828 与 0x7ffee406582c 也是差了4个字节,在16进制里8 + 4 = c,c就是12。

二分查找(leetcode704)

要求:要熟悉 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法

题目描述

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

输入: nums = [-1,0,3,5,9,12], target = 9     
输出: 4       
解释: 9 出现在 nums 中并且下标为 4
输入: nums = [-1,0,3,5,9,12], target = 2     
输出: -1        
解释: 2 不存在 nums 中因此返回 -1

提示:

  • 你可以假设 nums 中的所有元素是不重复的。
  • n 将在 [1, 10000]之间。
  • nums 的每个元素都将在 [-9999, 9999]之间。

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

文章讲解:

代码随想录

视频讲解:

手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili

二分查找易错点

到底是 while(left < right) 还是 while(left <= right)?

是right = middle呢,还是right = middle - 1呢?

写二分法经常容易写乱,主要就是因为对区间的定义没有想清楚,没有理解清楚

在while循环中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则

例如

如果是用 while(left <= right)

那么当 nums[mid] > target 时 要查找的数在做左边 这时右边界 right = mid - 1;

如果是用 while(left < right)

那么当 nums[mid] > target 时 要查找的数在做左边 这时右边界 right = mid;

这就是我们要根据区间的定义来操作的原因。

写二分法,区间的定义一般为两种

  • 左闭右闭:[left, right]
  • 左闭右开:[left, right)

解题思路&代码

用二分查找解这道题目的前提是:

  1. 数组为有序数组
  2. 数组中无重复元素

因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件

二分查找两个方法

  1. 左闭右闭
  2. 左闭右开

手撕二分查找

方法1:左闭右闭
class Solution {
    public int search(int[] nums, int target) {
        // 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
        if (target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }

        // 定义数组的左右边界
        int left = 0;
        int right = nums.length - 1;

        // 方法1:左闭右闭
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] > target) {// 要查找的数在左边
                right = mid - 1;
            } else if (nums[mid] < target) {// 要查找的数在右边
                left = mid + 1;
            } else if (nums[mid] == target) {//正好找到 直接返回
                return mid;
            }
        }
        //没找到目标值即要查找的数不存在
        return -1;
    }
}
  • 时间复杂度:O(log n)

方法2:左闭右开
class Solution {
    public int search(int[] nums, int target) {
        //定义左边界和右边界
        int left = 0;
        int right = nums.length;
        
        // 方法2:左闭右开
        while(left < right){
            int mid = (left + right) / 2;
            if(nums[mid] > target){//要查找的数在左边
                right = mid;
            }else if(nums[mid] < target){//要查找的数在右边
                left = mid + 1;
            }else if(nums[mid] == target){//正好找到 直接返回
                return mid;
            }
        }
        //没找到目标值即要查找的数不存在
        return -1;
    }
}
  • 时间复杂度:O(log n)

移除元素(leetcode27)

要求:

  1. 用暴力的解法,可以锻炼一下我们的代码实现能力,建议先把暴力写法写一遍
  2. 双指针法 是本题的精髓,今日需要掌握

题目描述

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

不要使用额外的数组空间,你必须仅使用 O(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],也会被视作正确答案。
输入: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

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

文章讲解:

代码随想录

视频讲解:

数组中移除元素并不容易! | LeetCode:27. 移除元素_哔哩哔哩_bilibili

数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。

数组中的位置是删除不了的 只能覆盖该位置中的数据

也就是说在下图的数组中,如果你要删除3的话 是删除不了该位置的,只能覆盖它的数据

在数组中删除元素是这样的:把4往前移动一位把3覆盖掉,再把5往前移动一位,把4覆盖掉,以此类推后面的数据全部往前移动,最后一个位置放什么都无所谓,可以放原来的数。

解题思路&代码

一遍不懂 二遍 二遍不懂就看第三遍,算法最重要的就是思路

方法1:暴力解法

这个题 暴力的解法就是使用两层for循环

第一个for循环用来:遍历数组中的所有元素

第二个for循环用来:替换数组元素的值

class Solution {
    public int removeElement(int[] nums, int val) {
        // 暴力法
        // 用一个变量来保存数组的大小
        int size = nums.length;
        for(int i = 0; i < size; i++){//第一个for循环用来遍历数组元素
            if(nums[i] == val){//发现需要移除的元素
                for(int j = i + 1; j < size; j++){//将那个数之后的所有元素向前覆盖一位
                    nums[j - 1] = nums[j];//把后一个元素赋给前一个元素所在的地址
                }
                i--;//因为下标i以后得数值都向前移动了一位,所以i也向前移动一位
                size--;//因为删除了一个元素 所以此时数组大小要-1
            }
        }
        return size;
    }
}
  • 时间复杂度:O(n^2)

方法2:双指针法

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作

快指针与慢指针

快指针用来寻找新数组中的需要的元素

就是删除我们目标值之后的元素 就是新数组中的元素

当我们用快指针获取到新数组需要的元素时 我们就用慢指针来赋值给新数组

就是把快指针获取到的值 赋值给慢指针就OK了

我们要想删除数组中的某一个元素

那我们的新数组中是不是就不能包含该元素

那么当我们的快指针指向的值 不等于我们要删除的目标元素

那我们就可以把该值赋给新数组

也就是把我们快指针所获取到的值,赋值给新数组所对应的下标位置

假设我们要删除一个数组中的元素3

删除元素3完成

新数组中没有元素3

同理我们在原数组中也能执行同样的操作,可以不用new一个新的数组,直接在原数组上进行元素的移除

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

代码示例如下:

class Solution {
    public int removeElement(int[] nums, int val) {
        //快慢指针
        //慢指针slowIndex,快指针fastIndex
        int slowIndex = 0;
        for(int fastIndex = 0; fastIndex < nums.length; fastIndex++){
            if(nums[fastIndex] != val){
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }
}
  • 时间复杂度:O(n)

各位学习C语言的初学者,如果有问题随时都可以来问我,我会随时为您解答!欢迎大家与我一起学习,互相进步。

我的C语言专栏:C语言基础语法(超详细)_☆光之梦☆的博客-CSDN博客

创作不易,👍 +⭐ +📝(一键三连) 是对博主最大的鼓励与支持哦。

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

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

相关文章

Ubuntu安装K8S(1.28版本,基于containrd)

原文网址&#xff1a;Ubuntu安装K8S(1.28版本&#xff0c;基于containrd&#xff09;-CSDN博客 简介 本文介绍Ubuntu安装K8S的方法。 官网文档&#xff1a;这里 1.安装K8S 1.让apt支持SSL传输 sudo apt-get update sudo apt-get -y install apt-transport-https ca-certi…

【算法与数据结构】860、LeetCode柠檬水找零

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题的思路比较简单&#xff0c;首先要保存收到的零钱&#xff0c;其次计算找零&#xff0c;最后分解找…

git的常用命令以及在可视化工具中的使用方法

一.引言 想当初在刚进公司的时候&#xff0c;对于git的使用非常不熟悉&#xff0c;特别是分支的概念&#xff0c;导致开发效率变低&#xff0c;故通过此文章&#xff0c;总结git的使用经验 二.Git 常用命令详解 2.1 git clone [url]: 克隆远程仓库到本地 刚开始时&#xff0c…

Anaconda 环境中安装OpenCV (cv2)

1、使用Anaconda 的对应环境&#xff0c;查看环境中的Python版本号 (1)使用Anaconda 查看存在的环境&#xff1a;conda info --env (2)激活环境&#xff1a;conda activate XXX 2、根据版本号&#xff0c;下载对应的 python-opencv 包 &#xff08;1&#xff09;选择国内源的…

K8S网络类型

k8s的网络类型 k8s的通信模式 1 pod内部之间容器与容器之间的通信&#xff0c;在同一个pod中容器是共享资源和网络&#xff0c;使用同一个网络命名空间&#xff0c;可以直接通信 2 同一个node节点之内&#xff0c;不同pod之间的通信&#xff0c;每个pod都有一个全局的真实ip地…

RabbitMQ 报错:Failed to declare queue(s):[QD, QA, QB]

实在没想到会犯这种低级错误。 回顾整理一下吧&#xff1a; 原因&#xff1a;SpringBoot主配置类默认只会扫描自己所在的包及其子包下面的组件。其他位置的配置不会被扫描。 如果非要使用其他位置&#xff0c;就需要在启动类上面指定新的扫描位置。注意新的扫描位置会覆盖默…

深入浅出:分布式、CAP 和 BASE 理论(荣耀典藏版)

大家好&#xff0c;我是月夜枫&#xff0c;一个漂泊江湖多年的 985 非科班程序员&#xff0c;曾混迹于国企、互联网大厂和创业公司的后台开发攻城狮。 在计算机科学领域&#xff0c;分布式系统是一门极具挑战性的研究方向&#xff0c;也是互联网应用中必不可少的优化实践&…

如何在Android Termux中使用SFTP实现远程传输文件

文章目录 1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问5. 配置固定远程连接地址6、结语 SFTP&#xff08;SSH File Transfer Protocol&#xff09;是一种基于SSH&#xff08;Secure Shell&#xff09;安全协议的文件传输协议。与FTP协议相比&#xff0c;SFT…

超时控制:Go语言下的网络请求与时间赛跑

开场白&#xff1a;在互联网的世界里&#xff0c;我们经常要与各种API打交道。有时&#xff0c;这些API可能会因为各种原因而变得“慢条斯理”&#xff0c;这时&#xff0c;超时控制就显得尤为重要了。今天&#xff0c;我们就来聊聊如何在Go语言中实现HTTP请求的超时控制&#…

千巡翼X4轻型无人机 赋能智慧矿山

千巡翼X4轻型无人机 赋能智慧矿山 传统的矿山测绘需要大量测绘员通过采用手持RTK、全站仪对被测区域进行外业工作&#xff0c;再通过方格网法、三角网法、断面法等进行计算&#xff0c;需要耗费大量人力和时间。随着无人机航测技术的不断发展&#xff0c;利用无人机作业可以大…

Linux磁盘管理与文件系统

目录 一、磁盘的数据结构 二、MBR和GPT磁盘 1、分区介绍 1.1分区的原因 1.2分区的优点 1.3分区的缺点 1.4分区的类型 2、MBR分区 3、GPT分区 三、文件系统 1、xfs&#xff1a; centos 7默认的文件系统 2、ext4&#xff1a;centos 6默认的文件系统 四、磁盘分区的…

Docker 概念介绍

1、Docker 简介 Docker一个快速交付应用、运行应用的技术: 可以将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;可以迁移到任意Linux操作系统运行时利用沙箱机制形成隔离容器&#xff0c;各个应用互不干扰启动、移除都可以通过一行命令完成&#xff0c;方便快捷 Doc…

three.js实现3D汽车展厅效果展示

项目搭建 本案例还是借助框架书写three项目&#xff0c;借用vite构建工具搭建vue项目&#xff0c;搭建完成之后&#xff0c;用编辑器打开该项目&#xff0c;在终端执行 npm i 安装一下依赖&#xff0c;安装完成之后终端在安装 npm i three 即可。 因为我搭建的是vue3项目&…

HPCC:高精度拥塞控制

HPCC&#xff1a;高精度拥塞控制 文章目录 HPCC&#xff1a;高精度拥塞控制摘要1 引言1.1 背景1.2 现有CC的局限性1.3 HPCC的提出 2 研究动机2.1 大型RDMA部署2.2 RDMA目标2.3 当前RDMA CC中的权衡DCQCNTIMELY 2.4 下一代高速CC 3 技术方案3.1 INT3.2 HPCC设计3.3 HPPC的参数 4…

Ubuntu20.04服务器使用教程(安装教程、常用命令、故障排查)持续更新中.....

安装教程&#xff08;系统、驱动、CUDA、CUDNN、Pytorch、Timeshift、ToDesk&#xff09; 制作U盘启动盘&#xff0c;并安装系统 在MSDN i tell you下载Ubuntu20.04 Desktop 版本&#xff0c;并使用Rufus制作UEFI启动盘&#xff0c;参考UEFI安装Ubuntu使用GPTUEFI模式安装&am…

学习笔记:数据挖掘与机器学习

文章目录 一、数据挖掘、机器学习、深度学习的区别&#xff08;一&#xff09;数据挖掘&#xff08;二&#xff09;机器学习&#xff08;三&#xff09;深度学习&#xff08;四&#xff09;总结 二、数据挖掘体系三、数据挖掘的流程四、典型的数据挖掘系统 一、数据挖掘、机器学…

Unity引擎有哪些优点

Unity引擎是一款跨平台的游戏引擎&#xff0c;拥有很多的优点&#xff0c;如跨平台支持、强大的工具和编辑器、灵活的脚本支持、丰富的资源库和强大的社区生态系统等&#xff0c;让他成为众多开发者选择的游戏开发引擎。下面我简单的介绍一下Unity引擎的优点。 跨平台支持 跨…

Pycharm2023版本:Python远程调试配置详解

工欲善其事&#xff0c;必先利其器 首先你需要选择一个专业版本的pycharm&#xff0c;社区版本不支持远程配置功能&#xff0c;专业版下载地址&#xff1a;Pycharm 2023 双击程序进行安装&#xff0c;30天内免费试用&#xff0c;如果想要永久使用&#xff0c;办法你懂的&…

基于机器视觉工业相机的Raw图像和Bitmap图像的保存和转换(C#代码,UI界面版)

基于机器视觉工业相机的Raw图像和Bitmap图像的保存和转换&#xff08;C#代码&#xff0c;UI界面版&#xff09; 工业相机图像格式工业相机实现Raw图像和Bitmap图像的保存和转换的技术背景在相机SDK中获取图像转换图像的代码分析工业相机回调函数里保存Bitmap图像数据工业相机图…

运维工程师的出路探索

目录 1 前言2 运维半衰期&#xff1a;技能演化与职业挑战3 运维工程师&#xff1a;技术升级与多维发展之道3.1 持续学习与更新技能3.2 培养解决问题的能力3.3 拓展视野3.4 跨界合作 4 塑造未来&#xff1a;运维工程师的多样化职业道路探索4.1 云计算专家4.2 自动化与DevOps4.3 …