二分法-Leetcode

这篇博客探讨了在LeetCode中使用二分法解决不同类型的问题,包括整数相除(29. Divide Two Integers)、寻找目标值的范围(34. Search for a Range)、指数计算(50. Pow(x, n))、平方根求解(69. Sqrt(x))、二维矩阵搜索(74. Search a 2D Matrix)以及找到数组中的峰值元素(162. Find Peak Element)。通过分析和展示简洁的代码实现,阐述了二分法在不同场景下的高效运用。" 115882761,10539497,MATLAB在数字电路仿真的应用与技巧,"['MATLAB仿真', '数字电路设计', '电路验证', '电路调试', '电路仿真']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

29. Divide Two Integers

整数相除,不能用除法或者乘法或者取模。如果溢出,返回INT_MAX。
重点:左移乘2:<<
思路:这里模拟整数相除,本质就是计算一个被除数包括多少个除数,这包含多少个,如果一个个累加肯定是太慢了,可以考虑二分的思路,两倍两倍来计算,利用位运算,每一步移位来计算。这里还需要注意的两个问题,一个是溢出,一个是符号。溢出考虑两种情况:

divisor = 0;
dividend = INT_MIN and divisor = -1
(because abs(INT_MIN) = INT_MAX + 1).

符号计算:

int flag = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;

代码:

class Solution {
public:
    int divide(int dividend, int divisor) {
        if (divisor == 0 || (dividend == INT_MIN && divisor == -1)) return INT_MAX;
        long long m = abs((long long)dividend), n = abs((long long)divisor), res = 0;
        int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;
        if (n == 1) return sign == 1 ? m : -m;
        while (m >= n) {
            long long t = n, p = 1;
            while (m >= (t << 1)) {
                t <<= 1;
                p <<= 1;
            }
            res += p;
            m -= t;
        }
        return sign == 1 ? res : -res;
    }
};

34. Search for a Range

升序序列中,找到目标值的起始位置和终止位置。时间复杂度O(logn)
二分查找,找到后左右移动

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

优雅版代码:

vector<int> searchRange(int A[], int n, int target) {
    int i = 0, j = n - 1;
    vector<int> ret(2, -1);
    // Search for the left one
    while (i < j)
    {
        int mid = (i + j) /2;
        if (A[mid] < target) i = mid + 1;
        else j = mid;
    }
    if (A[i]!=target) return ret;
    else ret[0] = i;

    // Search for the right one
    j = n-1;  // We don't have to set i to 0 the second time.
    while (i < j)
    {
        int mid = (i + j) /2 + 1;   // Make mid biased to the right
        if (A[mid] > target) j = mid - 1;  
        else i = mid;               
    }
    ret[1] = j;
    return ret; 
}

50. Pow(x, n)

实现:pow(x, n).

class Solution {
public:
    double myPow(double x, int n) { 
    if(n==0) return 1;
    //对负数的处理,防止溢出
    if(n<0) return (1/x)*myPow(1/x,-(n+1));
    return n%2==0 ? myPow(x*x, n/2) : x*myPow(x*x, n/2);
}
};

69. Sqrt(x)

实现:int sqrt(int x).

class Solution {
public:
    int mySqrt(int x) {
        int start = 0, end = x/4 + 1;
        //二分查找的套路
        while (start + 1 < end) {
            int mid = (end - start) / 2  + start;
            //如果直接比较,可能存在越界的问题
            if (mid < (x / mid)) start = mid;
            else if (mid > (x / mid))   end = mid;
            else return mid;
        }
        if (end  <= (x / end)) return end;
        else return start;
}
};

74. Search a 2D Matrix

写出一个高效的算法来搜索 m × n矩阵中的值。
这个矩阵具有以下特性:
* 每行中的整数从左到右是排序的。
* 每行的第一个数大于上一行的最后一个整数。
因为条件中有每行的第一个数大于上一行的最后一个整数。所以先对每行的第一个数来进行一个二分查找,找到最后一个不大于target的数然后再对这一行进行二分查找即可,这样首先对每行的第一个数查找复杂度为O(logn),再对某一行进行查找,复杂度为O(logn),所以为O(logn)。

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if (matrix.empty() || matrix[0].empty()) return false;
        int start = 0, end = matrix.size() - 1;
        while (start + 1 < end) {
            int mid = (end - start) / 2 + start;
            if (matrix[mid][0] < target) start = mid;
            else end = mid;
        }
        int new_start = 0, new_end = matrix[0].size() - 1;
        int index = matrix[end][0] <= target ? end : start;
        if (matrix[start][0] > target) return false;
        while (new_start + 1 < new_end) {
            int mid = (new_end - new_start) / 2 + new_start;
            if (matrix[index][mid] < target) new_start = mid;
            else if (matrix[index][mid] > target) new_end = mid;
            else return true;
        }
        if (matrix[index][new_start] == target) return true;
        if (matrix[index][new_end] == target) return true;
        return false;
    }
};

162. Find Peak Element

题目:给出一个整数数组(size为n),其具有以下特点:

相邻位置的数字是不同的
假设num[-1] = num[n] = -∞
如果某个元素大于临近元素,就称其为峰值。数组中可能存在多个峰值,返回其中任意一个峰值的位置。
样例:给出数组[1, 2, 1, 3, 4, 5, 7, 6]返回1, 即数值 2 所在位置, 或者6, 即数值 7 所在位置。

思路:二分法,这里根据中间值和临近值,可以分为四种情况:
第一种情况:当前点就是峰值,直接返回当前值。
第二种情况:当前点是谷点,不论往那边走都可以找到峰值。
第三种情况:当前点处于下降的中间,往左边走可以到达峰值。
第四种情况:当前点处于上升的中间,往右边走可以达到峰值。
每种情况,把有答案的一半保留下来即可。

 if (nums.empty()) return -1;
        if (nums.size() == 1) return 0;
        int start = 0, end = nums.size() - 1;
        while (start + 1 < end) {
            int mid = (end - start) / 2 + start;
            if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1])
                return mid;
           // else if (nums[mid] > nums[mid - 1] && nums[mid] < nums[mid + 1])
             //   start = mid;
            else if (nums[mid] < nums[mid - 1] && nums[mid] > nums[mid + 1])
                end = mid;
            else
                start = mid;
        }
        if ((start == 0 && nums[start] > nums[start + 1]) || (nums[start] > nums[start - 1] && nums[start] > nums[start + 1]))
            return start;
        if ((end == nums.size()-1 && nums[end] > nums[end - 1]) || (nums[end] > nums[end - 1] && nums[end] > nums[end + 1]))
            return end;

精简版,参考别人的代码:We just check the mid and mid+1 element and recheck the bigger side as the bigger side will have the peak element for sure.

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int start=0, end=nums.size()-1;
        while(end>start){
            int mid=(start+end)/2;
            if(nums[mid] < nums[mid+1])  start=mid+1;
            else end=mid;
        }
        return start;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值