【刷题日记001】数组——二分法

本系列主要用来记录2022年寒假刷LeetCode一些笔记。写博客的目的是为了敦促自己在家不要摆烂努力学习otz。主要是根据 代码随想录 的刷题计划进行的。代码是LeetCode官方题解及代码随想录提供的版本。

二分查找

如果题目中说了有序数组,数组元素不重复则考虑使用二分查找。二分查找要注意边界条件。在二分查找过程中,在while寻找中每一次边界处理都要根据区间定义来操作。
区间定义分为左闭右闭[left,right]左闭右开[left,right) 两种。

左闭右闭[left,right]

int left = 0, right = nums.size()-1;//定义区间左闭右闭
while(left <= right){ // left==right时区间依旧有效,故采用<=
	int mid = (right - left) / 2 + left; // 与(left+right)/2等价,这么写是为了防止相加时溢出。
	if(nums[mid] > target){
		right = mid - 1; //如果中间值比target大,说明要在更小的一半寻找。	
	}
	else if(nums[mid] < target){
		left = mid + 1; //如果中间值比target大,说明要在更小的一半寻找。	
	}
	else return mid; //若target == nums[mid]表示找到,返回位置
}
return -1;//未找到

左闭右开[left,right)

int left = 0, right = nums.size();//定义区间左闭右开[left, right)
while(left < right){ // left==right时区间无效,故采用<
   int mid = (right - left) / 2 + left; // 与(left+right)/2等价,这么写是为了防止相加时溢出。
   if(nums[mid] > target){
   	// 这里right = mid是因为寻找的区间是左开右闭
   	// 下一个查询区间依旧不会比较nums[mid]
   	right = mid ; //如果中间值比target大,说明要在更小的一半寻找。	
   }
   else if(nums[mid] < target){
   	left = mid + 1; //如果中间值比target大,说明要在更小的一半寻找。	
   }
   else return mid; //若target == nums[mid]表示找到,返回位置
}
return -1;//未找到

leetcode相关题目

704.二分查找

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

class Solution {
public:
    int search(vector<int> & nums, int target)
{
    int low = 0, high = nums.size() - 1;
    int mid;
    while (low <= high)
    {
        mid = (high - low)/2 + low;//高效算mid mid = low+high/2有可能溢出
        if(nums[mid] > target)
            high = mid - 1;
        else if(nums[mid] < target)
            low = mid + 1;
        else return mid;
    }
    return -1;
}
};

35.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

题解:和上题类似。若查找失败时,返回插入位置为当前low指向的位置。因为二分法会找到离目标值最近的值得前一个值,若target < nums[mid]则low会指向mid后得一个数。即要插入的位置【手动模拟一下】

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

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

题目:给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

题解:这道题有点难,因为涉及到多个重复数字。这里寻找target在数组中的位置分三种情况:

  • target在数组范围外,return{-1,-1}
  • target在数组范围内,但不存在target,return{-1,-1}
  • target在数组范围内,且存在target,return target的左右边界范围

再利用二分法找到左右边界。

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        // 处理三种情况
        int leftBoard = getLeftBoard(nums, target);
        int rightBoard = getRightBoard(nums, target);
        if(leftBoard == -2 || rightBoard == -2) return {-1, -1};
        if(rightBoard -leftBoard > 1) return {leftBoard + 1, rightBoard - 1};
        return {-1, -1};

    }
private:
// 二分法寻找右边界
    int getRightBoard(vector<int>& nums, int target)
    {
        int low = 0, high  = nums.size() - 1;
        // 记录是否存在右边界
        int rightBoard = -2;
        while(low <= high){
            int mid = (high - low) / 2 + low;
            if(nums[mid] > target)
                high = mid - 1;
            else{
                low = mid + 1;
                rightBoard = low;
            }
        }
        return rightBoard;
    }
//寻找左边界
    int getLeftBoard(vector<int>& nums, int target)
    {
        int low = 0, high = nums.size()-1;
        int leftBoard = -2;
        while(low <= high)
        {
            int mid = (high - low) / 2 + low;
            if(nums[mid] >= target)
            {
                high = mid -1;
                leftBoard = high;
            }
            else
                low = mid + 1;
        }
        return leftBoard; 
    }
    
};

69.Sqrt(x)

题目:给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
题解:用二分法判断[0,x]之间的数的平方与x的关系。找到平法比x小的最大整数。

class Solution {
public:
    int mySqrt(int x) {
        int low = 0, high = x;
        int ans = -1;
        while(low <= high){
            int mid = (high - low) / 2 + low;
            if((long long) mid * mid <= x){
                ans = mid;
                low = mid + 1;
            }               
            else high = mid - 1;
            }
        return ans;
    }
};

367.有效的完全平方数

题目:给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
题解:与上题相似,用二分法找到[0,num]之间平方等于num的数。

class Solution {
public:
    bool isPerfectSquare(int num) {
        int low = 0, high = num;
        int ans = -1;
        while(low <= high)
        {
            int mid = (high - low) / 2 + low;
            if((long long) mid * mid < num)
                low = mid + 1;
            else if((long long) mid * mid > num)
                high = mid - 1;
            else return true;
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值