首页 > 编程语言 >代码随想录算法训练营Day01 | LeetCode704 二分查找、Leetcode27 移除元素

代码随想录算法训练营Day01 | LeetCode704 二分查找、Leetcode27 移除元素

时间:2023-04-14 21:22:05浏览次数:50  
标签:元素 target LeetCode704 int nums 随想录 mid fast 移除

今日学习的视频和文章

  • 代码随想录数组基础 复习基础知识
  • 代码随想录 二分查找
  • 代码随想录 移除元素

LeetCode704 二分查找

题目链接:704. 二分查找 - 力扣(Leetcode)

以前学二分查找的时候,真的一直搞不清楚怎么操作左边界和有边界,以及循环的终止条件是什么,总是自己慢慢调试出来,然后下一次又忘了。直到看见了 Carl 哥的讲解,让我有种醍醐灌顶的感觉。不仅是二分查找,写其他算法的时候,记得循环不变量原则也让我的思路清楚很多。

循环不变量原则,在 while 中每一次对边界的操作都要严格遵循区间的定义来操作,区间的定义就是循环不变量。

左闭右闭区间

  • 初始化,区间的定义为左闭右闭区间,即[l, r]

那么应该这样初始化:

int l = 0;
int r = nums.size() - 1;//r能取等号,所以应该是数组nums的最大下标
int mid = (l + r) / 2;
  • 考虑边界条件,l == r 时左闭右闭区间[l, r]是合理的,所以while语句的循环条件应为:
while (l <= r) {
    /* 二分查找 */
}
  • target < nums[mid],即target落在左边区间,nums[mid]已经被查找过,所以调整右边界r时,应该不包括mid
while (l <= r) {
    if (target < nums[mid]) {
        r = mid - 1;
    }
    /* ... */
}
  • nums[mid] < target,即target落在右边区间,nums[mid]也已经被搜索过,所以调整左边界时,也不应该包括mid
while (l <= r) {
    if (target < nums[mid]) {
        r = mid - 1;
    }
    else if (nums[mid] < target) {
        l = mid + 1;
    }
}
  • nums == target,即找到目标,直接返回mid即可。

  • 综合以上分析得到完整题解代码:

int search(vector<int>& nums, int target) {
    int l = 0;
    int r = nums.size() - 1;
    int mid = (l + r) / 2;
    while (l <= r) {
        if (target < nums[mid]) {
            r = mid - 1;
        }
        else if (nums[mid] < target) {
            l = mid + 1;
        }
        else {
            return mid;
        }
        mid = (l + r) / 2;
    }
    return -1;
}

左闭右开区间

  • 初始化,左闭右开区间[l, r)。则r = nums.size()
int l = 0;
int r = nums.size();
int mid = (l + r) / 2;
  • 考虑边界条件,对于左闭右开区间[l, r)而言,l == r是不合理的,所以while的循环条件应为l < r
  • 调整左边界时,mid是被搜索过的,l可以取等号,所以不应该包括mid,即l = mid + 1
  • 调整右边界时,mid被搜索过,r不能取等号,正好将mid赋值给r,下一次循环的搜索范围正好不包括现在的mid。如果r = mid - 1,下一次循环的区间为[l, mid - 1),少包含了nums[mid - 1]这个元素,显然逻辑是有问题的。

左闭右开区间的完整题解代码。

int search(vector<int>& nums, int target) {
    int l = 0;
    int r = nums.size();
    int mid = (l + r) / 2;
    while (l < r) {
        if (target < nums[mid]) {
            r = mid;
        }
        else if (nums[mid] < target) {
            l = mid + 1;
        }
        else {
            return mid;
        }
        mid = (l + r) / 2;
    }
    return -1;
}

LeetCode27 移除元素

暴力解法

  • 暴力解法,先移除元素,再让未移除的元素把空位补上。
int removeElement(vector<int>& nums, int val) {
    int n = nums.size();
    int del = 0;
    for (int i = 0; i < n - del; i++) {
        if (nums[i] == val) {
            int j = i;
            while (j + 1 < n) {
                nums[j] = nums[j + 1];
                j++;
            }
            del++;
            i--;//这里要注意判断下一个元素是否等于 val,否则可能会漏掉 val 的元素
        }
    }
    return n - del;
}

以上算法的时间复杂度为O(n^2)

双指针法(快慢指针法)

  • 删除数组元素本质是用后面的元素覆盖前面的元素,让元素在空间上保持连续分布。那么,只需要判断哪个元素保留,哪个元素被覆盖,就可以在一次遍历中完成删除数组元素。
  • slow指针指向要被覆盖的元素位置,用fast指针表示当前遍历到的元素的位置。在遍历数组时,用nums[fast]nums[slow]赋值。
    1. fast指向要删除的元素时,fast直接+ 1而不用 nums[fast]nums[slow] 赋值,此时fast已经跳过了要被删除的元素。
    2. 然后,当 fast 指向不会被删除的元素时,用nums[fast]nums[slow]赋值,此时,被保留的元素覆盖了要被删除的元素的位置,完成了一个元素的删除,并且保持了元素在空间上的连续分布。

完整题解代码如下:

int removeElement(vector<int>& nums, int val) {
        int n = nums.size();
        int fast = 0;
        int slow = 0;
        for (;fast < n; fast++) {
            if (nums[fast] != val) {
                nums[slow++] = nums[fast];
            }
        }
        return n - fast + slow;
    }
};

标签:元素,target,LeetCode704,int,nums,随想录,mid,fast,移除
From: https://www.cnblogs.com/bonfire-A-/p/17319987.html

相关文章

  • js中一个移除对象中子数组中空值的函数
    js中一个移除对象中子集数组中空值(null,undefined)的函数functionremoveNull(obj){letdelarr=[];for(letiinobj){//排除法寻找对象类型if(typeof(obj[i])==='boolean'||typeof(obj[i])==='string'||typeof(obj[i])==......
  • 203. 移除链表元素
    参考链接:代码随想录题目描述:解题思路:由单链表的特殊性,如果删除的是头节点应该怎么操作呢?这里就涉及如下链表操作的两种方式:-直接使用原来的链表进行删除操作-设置一个虚拟头节点进行删除操作第一种操作: 移除头节点和移除其他节点的操作是不一样的,因为链表的其他节点......
  • 27. 移除元素
    力扣题目链接给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。示例1:......
  • day 38代码随想录 509. 斐波那契数 | 使用最小花费爬楼梯
    斐波那契数,通常用 F(n)表示,形成的序列称为斐波那契数列。该数列由 0和1开始,后面的每一项数字都是前面两项数字的和。也就是:F(0)=0,F(1) =1F(n)=F(n-1)+F(n-2),其中n>1给你n,请计算F(n)。示例1:输入:2输出:1解释:F(2)=F(1)+F(0)=1+0=1因为......
  • 代码随想录Day22-Leetcode235. 二叉搜索树的最近公共祖先,701.二叉搜索树中的插入操作,4
    235.二叉搜索树的最近公共祖先题目链接:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/又玩了一天,手又生疏了好多;这道题看了题解,先用公共解法了,之前的题没刷,就给现在留坑了/***Definitionforabinarytreenode.*functionTree......
  • fragment的查找和移除
    FragmentManagerfragmentmanger=getSupportFragmentManager();FragmentTransactionfragmenttransaction=fragmentmanager.begintransaction();//这一步不进行也可以查找Fragmentfragment=fragmentManager.findFragmentById(R.id.fragment);if(fragment!==null){......
  • 代码随想录Day20-Leetcode654.最大二叉树,617.合并二叉树,700.二叉搜索树中的搜索,98.验
    654.最大二叉树题目链接:https://leetcode.cn/problems/maximum-binary-tree/基本的模拟思路很快/***Definitionforabinarytreenode.*functionTreeNode(val,left,right){*this.val=(val===undefined?0:val)*this.left=(left===undefined......
  • 快慢指针-leetcode27移除元素
    给你一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用O(1)额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。说明:为什么返回数值是整数,但输......
  • 力扣---面试题 02.01. 移除重复节点
    编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。示例1:输入:[1,2,3,3,2,1]输出:[1,2,3]示例2:输入:[1,1,1,1,2]输出:[1,2]提示:链表长度在[0,20000]范围内。链表元素在[0,20000]范围内。进阶:如果不得使用临时缓冲区,该怎么解决?来源:力扣(LeetC......
  • 移除元素
    给你一个数组nums 和一个值val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用O(1)额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。输入:nums=[3,2,2,3],val=3输......