【二分查找】 二分查找mid值溢出问题

简介: 【二分查找】 二分查找mid值溢出问题

 今天突然想起来二分查找 求mid中间值会溢出的问题,便查找资料和自己思考记录一下这个问题。

二分查找时,我们往往会见到以下三种方法来求mid中间值

1.正常思路

mid = (left + right) / 2;

2.防溢出写法

mid = left + (right - left)/2;

3.位运算 也是防溢出 无符号位元素符的优先级较低,所以括起来

mid = left + ((right - left)>>2);

那么为什么第一种方法会溢出呢?

我之前学二分的时候,当时是两种写法都有人用,但是第二种方法说是可以防止溢出,我当时也没有在意,今天早上醒来打开手机看见二分,突然想到这个问题了,所以想记录一下这个问题;

1.第一种方法可能会溢出原因

一般我们都是定义左边界(left)和右边界(right)都使用 int 类型,如果 left 和 right 足够大,mid = (left + right)/2,可能会由于 left+right 导致 int 数据类型越界。

int占用4字节32比特时的取值范围为  -2147483648~2147483647  假设left right 为1073741824

加在一起 left+right = 2147483648 超过了int的最大范围 此时就溢出了

如果超出int的最大范围 那么结果变成负数,(原本我不太理解为什么超出范围会变成负数,在网上查找资料了解到:
十进制数字存储在计算机时要转换为二进制。数字在累加的时候会不断进位,超过最大范围时符号位就变成了1,1表示的是负数,计算机就理解成这是个负数了(为原码,补码、反码部分的知识))

如下面这个例子

#include<iostream>
using namespace std;

int main()
{
    int left = 1073741824; 
    int right = 1073741824;

    int result1 = (left + right) / 2;  
    int result2 = left + (right - right) / 2; 


    cout << "result1:" << result1 << endl;
    cout << "result2:" << result2 << endl;

    system("pause");

    return 0;
}

//运行结果
result1:-1073741824
result2:1073741824

而写成第二种方法 mid = left +(right -left)/2 的就会相对安全,(right - left)使用减法不会超出最大的整型范畴;给第二种方法通分一下就和第一种方法的式子一样。

写成第三种方法 mid = left +((rightt-left)>>2) 位运算,(效率是挺高的,就是嘛,不易懂hh)>>表示右位移运算符,把操作数的二进制码右位移指定位数,左边空出来的位以原来的符号位填充。原来是负数就填充1,原来是正数就填充0。符号位不变。

下面附二分板子(左闭右闭型,个人喜欢这种嘿嘿)

class Solution {
public:

int search(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
    while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
        int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
        if (nums[middle] > target) {
            right = middle - 1; // target 在左区间,所以[left, middle - 1]
        } else if (nums[middle] < target) {
            left = middle + 1; // target 在右区间,所以[middle + 1, right]
        } else { // nums[middle] == target
            return middle; // 数组中找到目标值,直接返回下标
        }
    }
    // 未找到目标值
    return -1;
}

};

先这样啦~

相关文章
|
8月前
|
算法 测试技术 C#
C++二分算法:使数组严格递增
C++二分算法:使数组严格递增
|
10月前
|
算法 Java
折半查找算法[二分查找法]算法的实现和解决整数溢出问题~
折半查找算法[二分查找法]算法的实现和解决整数溢出问题~
|
3月前
|
机器学习/深度学习 算法 测试技术
【排序 贪心】3107. 使数组中位数等于 K 的最少操作数
【排序 贪心】3107. 使数组中位数等于 K 的最少操作数
【排序 贪心】3107. 使数组中位数等于 K 的最少操作数
|
3月前
|
算法 测试技术 C#
【二分查找】【map]436. 寻找右区间
【二分查找】【map]436. 寻找右区间
|
3月前
|
算法 程序员 索引
【算法训练-二分查找 一】【基本二分】二分查找、在排序数组中查找元素的第一个和最后一个位置
【算法训练-二分查找 一】【基本二分】二分查找、在排序数组中查找元素的第一个和最后一个位置
42 0
|
8月前
|
人工智能 算法 C++
C++ 二分查找算法:山脉数组中查找目标值
C++ 二分查找算法:山脉数组中查找目标值
|
Java 测试技术 C++
LeetCode 69. Sqrt(x)--(数组)--二分法查找 --简单
Implement int sqrt(int x). Compute and return the square root of x, where x is guaranteed to be a non-negative integer. Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned.
115 0
LeetCode 69. Sqrt(x)--(数组)--二分法查找 --简单
C++二分有关溢出的问题
C++二分有关溢出的问题
77 0
C++二分有关溢出的问题
|
算法
算法练习——(8)用下标排序
问题:给你n个无序的int整型数组arr,并且这些整数的取值范围都在0-20之间,要你在 O(n) 的时间复杂度中把这 n 个数按照从小到大的顺序打印出来。
【每日一题Day77】LC1802有界数组中指定下标处的最大值 | 二分查找+贪心
当数组和一定时,要使指定下标处的数值最大,应以该位置为中心,相邻位置以1为间隔梯度下降,直至数值等于1【贪心获得数组和】
90 0