数组理论基础

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

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

需要两点注意的是

  • 数组下标都是从0开始的。

  • 数组内存空间的地址是连续的

正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。也可以理解为数组的元素是不能删的,只能覆盖。

704.二分查找

力扣题目链接(opens new window)

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

示例 1:

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

示例 2:

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

提示:

  1. 你可以假设 nums 中的所有元素是不重复的。

  1. n 将在 [1, 10000]之间。

  1. nums 的每个元素都将在 [-9999, 9999]之间。

思路:

这道题目的前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的。

写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。

左闭右闭:

第一种写法,我们定义 target 是在一个在左闭右闭的区间里,也就是[left, right]。

区间的定义这就决定了二分法的代码应该如何写,因为定义target在[left, right]区间,所以有如下两点:

  • while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=

  • if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1

代码如下:

class Solution {
public:int search(vector<int>& nums, int target) {int left = 0;int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2if (nums[middle] > target) {right = middle - 1; // target 在左区间,所以[left, middle - 1]} else if (nums[middle] < target) {left = middle + 1; // target 在右区间,所以[middle + 1, right]} else { // nums[middle] == targetreturn middle; // 数组中找到目标值,直接返回下标}}// 未找到目标值return -1;}
};

左闭右开

如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) 。

有如下两点:

  • while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的

  • if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]

代码如下:

class Solution {
public:int search(vector<int>& nums, int target) {int left = 0;int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <int middle = left + ((right - left) >> 1);if (nums[middle] > target) {right = middle; // target 在左区间,在[left, middle)中} else if (nums[middle] < target) {left = middle + 1; // target 在右区间,在[middle + 1, right)中} else { // nums[middle] == targetreturn middle; // 数组中找到目标值,直接返回下标}}// 未找到目标值return -1;}
};

27.移除元素

力扣题目链接(opens new window)

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

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

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 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],也会被视作正确答案。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

思路:

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

暴力解法:

两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。

代码如下:

// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public:int removeElement(vector<int>& nums, int val) {int size = nums.size();for (int i = 0; i < size; i++) {if (nums[i] == val) { // 发现需要移除的元素,就将数组集体向前移动一位for (int j = i + 1; j < size; j++) {nums[j - 1] = nums[j];}i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位size--; // 此时数组的大小-1}}return size;}
};

双指针法:

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

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组

  • 慢指针:指向更新 新数组下标的位置

代码如下:

// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:int removeElement(vector<int>& nums, int val) {int slowIndex = 0;for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {if (val != nums[fastIndex]) {nums[slowIndex++] = nums[fastIndex];}}return slowIndex;}
};

双指针法(头尾指针法):

基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素。

代码如下:

// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:int removeElement(vector<int>& nums, int val) {int leftIndex = 0;int rightIndex = nums.size() - 1;while (leftIndex <= rightIndex) {// 找左边等于val的元素while (leftIndex <= rightIndex && nums[leftIndex] != val){++leftIndex;}// 找右边不等于val的元素while (leftIndex <= rightIndex && nums[rightIndex] == val) {-- rightIndex;}// 将右边不等于val的元素覆盖左边等于val的元素if (leftIndex < rightIndex) {nums[leftIndex++] = nums[rightIndex--];}}return leftIndex;   // leftIndex一定指向了最终数组末尾的下一个元素}
};

注:本文为代码随想录学习笔记,原著请访问代码随想录 (programmercarl.com)

代码随想录Day01 | LeetCode704.二分查找、LeetCode27.移除元素相关推荐

  1. 代码随想录Day01:数组理论基础、二分查找、移除元素

    目录 数组理论基础.二分查找.移除元素 1.数组理论基础 2.Leetcode704.二分查找 方法一 左闭右闭: 方法二 左闭右开: 方法三 左开右开: 方法四 左开右闭: 3.Leetcode27 ...

  2. Day01.二分查找、移除元素

    Day01.二分查找.移除元素 0704.二分查找 题目链接:0704.二分查找 思路:二分查找,仅对有序数组有效.每次需要数组的中间值,与目标值比较大小,如果中间值比目标值大,说明目标值位置在lef ...

  3. 代码修炼Day1_LeetCode704二分查找27移除元素

    代码修炼Day1_LeetCode704二分查找&27移除元素 一些数组基本知识 数组下标都是从0开始的 数组内存空间的地址是连续的 题目链接: 力扣704二分查找 二分查找思想 针对升序数组 ...

  4. Leetcode 704.二分查找 27.移除元素 代码随想录day1

    本系列目的在于跟练代码随想录,以及记录自己在数据结构与算法方面的一些学习 704.二分查找 其实之前自己在随便刷题的时候看过这道题目,就是一个纯新手的大状态,第一次听到二分查找这样的东西,然后跟着题解 ...

  5. 代码随想录算法训练营第一天|704二分查找 27移除元素

    理论基础 1.数组是存放在连续内存空间上的相同类型数据的集合 2.数组可以方便的通过下标索引的方式获取到下标下对应的数据 3.数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要 ...

  6. 代码随想录01 | 704二分查找和27移除元素

    目录 一 .二分查找 1 二分查找 2 搜索插入位置 3  在排序数组中查找元素的第一个和最后一个位置 二.移除元素 一 .二分查找 1 二分查找 704 二分查找https://leetcode.c ...

  7. day1 704.二分查找 27.移除元素

    文章目录 704.二分查找 思路 代码实现 27.移除元素 思路 代码实现 704.二分查找 题目链接:704.二分查找 思路 使用二分法的前提条件: 1.有序数组 2.无重复元素 代码实现 左闭右闭 ...

  8. LeetCode--704.二分查找(C++)

    力扣链接 数组在内存中的空间地址是连续的 // // Created by lwj on 2022-03-30. // #include <iostream>using namespace ...

  9. 1、leetcode704 二分查找*

    leetcode 704 二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 ...

最新文章

  1. mysql 树形结构_再读MySQL索引-《高性能MySQL》索引手记
  2. requirednew基于xml配置日志不回滚_Elasticsearch配置IK分词器的远程词库
  3. 如何避免开发一款失败的产品?
  4. TensorFlow Serving + Docker + Tornado机器学习模型生产级快速部署
  5. 在.net中读写XML方法的总结[转]
  6. no.5_得到4升的水
  7. Linux 及其它类 Unix 系统的系统服务管理和控制程序(初始化系统/init system)简单梳理
  8. java 跨域 下载文件_文件下载重命名(可跨域)
  9. java输入方法有哪些内容_java 键盘输入多种方法
  10. layui 按钮点击一次后失效_electron-vue自定义边框后点击事件失效问题
  11. 活动目录数据库重定向或迁移
  12. CocoaPods管理iOS项目 2018年11月06日
  13. 【车辆计数】基于matlab形态学停车场车辆计数【含Matlab源码 628期】
  14. 恢复win7开机动画
  15. 计算机四级数据库分值分布,计算机四级数据库工程师考试成绩查询注意事项
  16. C - MaratonIME eats japanese food
  17. 你有没有一个御用冷笑话 说来听听~
  18. SQL server学习日志(二)创建表!手把手教你创建表,修改表,了解数据类型!超详细!
  19. HTML中关于<br>,<P>换行符的区别和使用影响
  20. 机械制造作业考研题目答案分享——加工方法、工序和夹紧

热门文章

  1. 数字孪生医院的智能化运营平台建设内容
  2. 期货交易中的重仓操作
  3. HMM(隐马尔可夫)
  4. 洛谷B2075 幂的末尾(解决pow数据爆炸,取后n位,不足补零)
  5. apache spark_使用Apache Spark SQL探索标普500和石油价格
  6. uniapp进行交互反馈
  7. 阿里云 Java发布SpringBoot项目,使用邮件服务发送失败原因整理
  8. openwrt 开启软看门狗
  9. 阅站无数的过我只推荐下面这些网站
  10. 游戏原画之女性角色绘画技巧-张聪-专题视频课程