第一天打卡(数组系列:二分和移除)

本文介绍了如何用C语言实现二分查找算法解决LeetCode题目704,以及如何原地移除数组中特定值的元素,包括初次解题思路、代码实现和视频学习总结。
摘要由CSDN通过智能技术生成

补day1,本篇代码为C语言版本。

一、二分查找

二分查找时数组都是有序数组,从小到大排列

1、力扣题目

704. 二分查找

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

示例:

输入: nums = [-1,0,3,5,9,12], target = 9

输出: 4

解释: 9 出现在 nums 中并且下标为 4

2、初次解题

思路:二分法相当于找到一个边界,每次先对半划分,然后根据条件,移动左右的边界值相互靠近,直到最后左右的划分的边界想邻,也就是当到达边界即left+1=right的时候,所以不满足该条件的时候应该一直循环。

(通俗点说就是一块空地,两边开始抢地盘,划分方法是每次剩下的空地对半抢,题目条件就是告诉你最后两边各自拥有地盘是多大。)

代码解释:

最终跳出循环的条件left+1=right

初始值是因为刚开始时土地都是空地,所以不是能下标为0和n-1之间的数(空地大小假设为n)并且根据最终判断条件left+1=right,要使得第一块下标为零的空地能够被抢到left+1=0才可以,所以left初始为-1,同理根据left=-1和判断条件要取到n-1,right应为n。

在数组为一个数时需注意数组是否会越界的问题

int search(int* nums, int numsSize, int target) {
    int left=-1,right=numsSize;
    int m=0;
    while(left+1!=right){
        m=(left+right)/2;//对半抢剩余的空地
        if(nums[m]<=target)
            left=m;
        else
            right=m;
    }
    if(left<0){
        if(nums[right]==target)
            return right;
        else 
            return-1;
    }//防止出现左边越界即数组种就一个数且该数大于target
    else{
        if(nums[left]==target)
            return left;
        else 
            return-1;
    }
}

3、学习视频

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

总结:按取值区间的不同分为[left,right],[left,right)和(left,right],不过一般是前两个,所以掌握前两种情况即可。同时无论在何种情况判断条件至少应满足left<right。

(1)左闭右闭区间

①初始化:根据取值区间,此时left和right的初始值就是数组的最小和最大的下标

②循环条件:条件应该是left<=righ(根据是否合法就可以判断,假设数组中就一个元素[0],因为左闭右闭,可知[0,0]是合理的,所以此时等于是可以的)

③更新区间:已经判判断过的数,无须再次判断,所以左边更新边界时需+1,右边更新边界时需-1。

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

(2)左闭右开区间

①初始化:根据取值区间,此时left和right的初始值就是数组的最小下标和最大下标+1。

②循环条件:条件应该是left<righ(假设数组中就一个元素[0],因为左闭右闭,可知[0,0)是非法的,所以此时等于是不可以的)

③更新区间:已经判判断过的数,无须再次判断,所以左边更新边界时为m+1,右边更新边界时为m。

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

4、总结

初次解题的思路能够解决一些划分问题,也就是分成左右两个范围,有些题目进行修改也可转化成类似的问题进行解决。

视频所学习到的方法,一般解题有四注意:注意初始化,注意判断条件,注意更新区间,注意返回值。

二、移除数组

1、力扣题目

27. 移除元素 - 力扣(LeetCode)

题目:给你一个数组 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],也会被视作正确答案。

2、初次解题

思想是覆盖,先寻找数组非val的个数(即最后数组个数),再分成前后两个部分循环来进行覆盖,前面为val的被后面非val的覆盖。

int removeElement(int* nums, int numsSize, int val) {
    int a=numsSize;
    for(int i=0;i<numsSize;i++){
        if(nums[i]==val)a--;
    }//寻找数组非val个数
    for(int i=a;i<numsSize;i++){//遍历后排
       if(nums[i]!=val){//非val时
            for(int j=0;j<a;j++){//循环前排
                if(nums[j]==val){//前排第一个为val
                    nums[j]=nums[i];
                    break;//val值被非val代替,并跳出循环
                }
            }    
        }         
    }
    return a;
}

3、学习视频

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

有两种方法:(1)使用库函数   (erase函数c++)       (2)使用双指针进行覆盖

此处主要掌握双指针方法:fast来进行遍历原先数组,slow来得到新数组。如果不是val则fast赋值给slow。

int removeElement(int* nums, int numsSize, int val) {
    int slow=0;
    for(int i=0;i<numsSize;i++){
        if(nums[i]!=val){
            nums[slow]=nums[i];
            slow++;
        }   
    }//此处i就是fast
    return slow;
}

4、总结

当进行同一个数组更新时,优先考虑双指针来进行更新。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值