代码随想录练习Day1|704.二分查找|27.移除元素

704.二分查找

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


思路讲解:

        典型的二分法,二分思路比较简单,注意使用前提:有序数组、无重复元素(有重复也可以使用,但要确定下标)

        具体查看代码随想录原文:二分查找思路讲解


代码 

左闭右闭(target在[left,right]区间里)

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;
        while(left<=right){
            int mid=left+((right-left)/2);  //防溢出
            if(nums[mid]>target)
                right=mid-1;
            if(nums[mid]<target)
                left=mid+1;
            if(nums[mid]==target)
                return mid;
        }
        return -1;
    }
};

        需要注意三点:

        1.不能简单写成 mid=(left+right)/2,当left和right都很大时,可能会溢出。

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

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

        复杂度:T = O(logn) M = O(1)


左闭右开(target在[left,right)里)

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size();
        while(left<right){
            int mid=left+((right-left)/2);  //防溢出
            if(nums[mid]>target)
                right=mid;
            if(nums[mid]<target)
                left=mid+1;
            if(nums[mid]==target)
                return mid;
        }
        return -1;
    }
};

        

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

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

       复杂度:T = O(logn) M = O(1)

27.移除元素

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

思路讲解

       这道题目重点在于理解数组的覆盖原则:如果数值等于val,那我们就可以直接将其进行覆盖,从而可以达成目标。具体覆盖有两种方法:暴力法--当判断该值是val时,将val后面的值前移一位进行覆盖。和双指针法:使用两个指针,第一个指针不断对数组进行遍历,寻找不为val的元素第二个指针对满足目标的元素进行存储,并对数组下标进行更新。

        具体查看代码随想录原文:移除元素思路讲解 


代码   

        暴力法

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
    int i=0;
    int j=0;
    int size=nums.size();
    for(i;i<size;i++){
        if(nums[i]==val){
            for(j=i+1;j<nums.size();j++){
                nums[j-1]=nums[j]; //集体右移一位
            }
            i--;
            size--;
        }
    }
    return size;
    }
};

        复杂度:T = O(n^2) M = O(1)

        双指针法   

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int findex=0;  //快指针
        int sindex=0;  //慢指针
        for(findex=0;findex<nums.size();findex++){
            if(nums[findex]!=val){
                nums[sindex]=nums[findex];
                sindex++;
                }
        }
        return sindex; //新长度
    }
};

        注意:典型的双指针法:通过一个双指针在一个for循环中完成了两个for循环的任务。 从而降低了时间复杂度。

        快指针:目标数组的下一个需要判断的值

        慢指针:目标数组的下一个需要添加的长度

复杂度:T = O(n) M = O(1)

附加题

        35.搜索插入位置

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;
        int mid=0;
        while(left<=right){
            mid=left+(right-left)/2;
            if(nums[mid]>target)
                right=mid-1;
            if(nums[mid]<target)
                left=mid+1;
            if(nums[mid]==target)
                return mid;
        }
        return left;
    }
};

  复杂度:T = O(nlogn) M = O(1)

        34. 在排序数组中查找元素的第一个和最后一个位置

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;
        while(left<=right){
            int mid=left+(right-left)/2;
            if(nums[mid]>target)
                right=mid-1;
            if(nums[mid]<target)
                left=mid+1;
            if(nums[mid]==target)
                {
                    int leftindex=mid;
                    int rightindex=mid;
                    while(leftindex>0&&nums[leftindex]==nums[leftindex-1])
                        leftindex--;  //找左边界
                    while(rightindex<nums.size()-1&&nums[rightindex]==nums[rightindex+1])
                        rightindex++;   //找右边界
                    return{leftindex,rightindex}; 
                }   
        }
        return{-1,-1};
    }
};

复杂度:T = O(nlogn) M = O(1)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值