5.6刷题记录(leecode35.搜索插入位置,leecode34. 在排序数组中查找元素的第一个和最后一个位置,leecode69.x的平方根,leecode367. 有效的完全平方数)

leecode35.搜索插入位置

这道题有一个要求,就是要求算法复杂度必须是logn。那么大家第一时间想到的应该就是用二分法做题
在这里插入图片描述
但是这个题目还有个要求,就是要如果没有查询到位置,就要返回元素应该插入的位置。我们来模拟以下加入没有找到相应元素。因为题目有说列表是有序的。
[1, 3, 5, 7]。假设我们的target是4,那么循环的left,right,middle应该为
第一次:left = 0, right = 3, middle = 1; 3 < target;left = middle+1=1
第二次:left=1,right=3,middle=2,5>target;right=middle-1=2
第三次:left=1,right=2,因为程序是下取整原则,每次二分到最后,肯定left和right都会落到两个相邻的值上,又因为数组是排序的。假设要找的taget不存在,left+right(left+1)的一半会等于left,这时nums[middle]小于target,left=middle+1。
这时左右届都是right,middle也会等于right,nums[right] > target, right= middle-1。这时循环会终止,因为right < left。这时我们要插入的值永远在right后面
上代码

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

            else if(nums[middle] < target){
                left = middle+1;
            }

            else{
                index = middle;
                break;
            }

        }

        //这里证明没有找到元素,就要确定元素插入的位置
        if(index == -1){
            index = right+1;
        }

        return index;

    }
};

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

今天的第二道题和别的题目有点不太一样,因为这次数组的元素虽然是按顺序排列但是是有重复的。
在这里插入图片描述
这就需要我们先找出左边界,再找出右边界

class Solution {
public:
        int getLeft(vector<int>& nums, int target){
            int left = 0;
            int right = nums.size()-1;
            int leftbord = -1;
            while(left <= right){
                int middle = (left+right)/2;
                if(nums[middle] < target){
                    left = middle+1;
                }
                else{
                    //当找到target的值的时候,也让右边界往左边逼近,这样可以找到左边界
                    right = middle-1;
                }

            }


            leftbord = right+1;
            return leftbord;
        }

        int getRight(vector<int>& nums, int target){
            int left = 0;
            int right = nums.size()-1;
            int rightbord = -1;

            //让左届往右边逼近
            while(left <= right){
                int middle = (left+right)/2;
                if(nums[middle] > target){
                    right = middle-1;
                }
                //最主要也是这一步,当target = nums[middle]时,也要让
                //左边界向右移动,这样跳出循环时才可以满足找到右边界
                else{
                    left = middle+1;
                }
            }

            rightbord = left-1;
            return rightbord;
        }

    vector<int> searchRange(vector<int>& nums, int target) {
        //这题一看就是二分,但是有些不一样这个题目中的数组有重复元素
        
        
        //那就遵循先找右边界再找左边界
        
        int right = getRight(nums, target);
        int left = getLeft(nums, target);

        //这里还要进行一次判定才可以输出
        if(right >= left) return{left, right};
        else return {-1, -1};

    }
};

leecode69.x的平方根

在这里插入图片描述
这道题第一次我用的是暴力解法。第一次被提示int可能储存不了那么多位。然后采用long来存储。因为经过我查看,他最后一次喂进去的数据是2147395600,虽然ii不超过int的最大储存,但是(i+1)(1+1)可能超过了。这个算法的算法复杂度是O(2N)。

class Solution {
public:
    int mySqrt(int x) {
        //因为用int类型会提示不够,所以用long long
        long result = -1;
        for(long i = 0; i <= x; i++){
            if(x >= i*i && x < (i+1)*(i+1)){
                result = i;
                break;
            }
        }

        return result;
    }
};

然后也可以使用二分法来做这道题目

class Solution {
public:
    int mySqrt(int x) {
        //因为用int类型会提示不够,所以用long long
        int left = 0;
        int right = x;
        int result = -1;
        
        if(x == 1) result = 1; 

        else{
            while((right-left) > 1){
            long middle = (left+right)/2;
            if(middle*middle <= x){
                left = middle;
            }

            else if(middle*middle > x){
                right = middle;
            }
            }
            result = left;
        }
        
        return result;

    }
};

写这个的时候遇到点小问题,还就是int不能储存的问题。还有1是特殊值。需要注意

class Solution {
public:
    int mySqrt(int x) 
    {
        if(x == 1)
            return 1;
        int left = 0;
        int right = x;
        while(right-left>1)
        {
            int m = (left+right)/2;
            if(x/m < m)
                right = m;
            else if(m*m <= x)
                left = m;
        }
        return left;
    }
};

仔细看关于二分法解题时判断条件的问题。x/m < m不会报错,而mm > x则会报错。这时为什么呢?引用leecode上一位大神的解释。
如果mm > 2的31次方-1的话,会越界,比如输入x = 2147395599的时候,1073697799 * 1073697799就越界了。 m
m > x 的话会先计算出m*m的值,再和x比较。所以这也是为什么第一种写法中如果用int来申明middle会发生如下错误
在这里插入图片描述

367. 有效的完全平方数

在这里插入图片描述
这道题就比较简单了,毕竟都做了这么多关于二分法的问题了

class Solution {
public:
    bool isPerfectSquare(int num) {
        if(num == 1) return true;
        else{
            int left = 0;
            int right = num;
            while(right - left > 1 ){
                int middle = (left+right)/2;
                if(middle > num/middle){
                    right = middle;
                }

                else{
                    left = middle;
                }

            }
            if(left*left!=num) return false;
            else return true;
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值