LeetCode-二分查找

1 二分查找介绍

1.1 在有序数组中查找目标值

int bSearch(vector<int>& nums, int target) 
{
    int l = 0, r = nums.size() - 1;
    while (l <= r)
    {
        int mid = l + ((r-l)>>1);
        if (nums[mid] == target)
        {
            return mid;
        }
        else if (nums[mid] < target)
        {
            l = mid + 1;
        }
        else
        {
            r = mid - 1;
        }
    }

    return -1;
}

1.2 二分查找的变体--查找第一个值等于目标值的元素

int bSearch(vector<int>& nums, int target) 
{
    int l = 0, r = nums.size() - 1;
    while (l <= r)
    {
        int mid = l + ((r-l)>>1);
        if (nums[mid] > target)
        {
            r = mid - 1;
        }
        else if (nums[mid] < target)
        {
            l = mid + 1;
        }
        else
        {
            if (mid == 0 || nums[mid - 1] != target)
            {
                return mid;
            }
            else
            {
                r = mid - 1;
            }
        }
    }

    return -1;
}

1.3 二分查找的变体--查找最后一个值等于目标值的元素

int bSearch(vector<int>& nums, int target) 
{
    int l = 0, r = nums.size() - 1;
    while (l <= r)
    {
        int mid = l + ((r-l)>>1);
        if (nums[mid] > target)
        {
            r = mid - 1;
        }
        else if (nums[mid] < target)
        {
            l = mid + 1;
        }
        else
        {
            if (mid == nums.size() - 1 || nums[mid + 1] != target)
            {
                return mid;
            }
            else
            {
                l = mid + 1;
            }
        }
    }

    return -1;
}

1.4 二分查找变体--查找第一个大于等于给定值的元素


int bSearch(vector<int>& nums, int target) 
{
    int l = 0, r = nums.size() - 1;
    while (l <= r)
    {
        int mid = l + ((r-l)>>1);
        if (nums[mid] >= target)
        {
            if (mid == 0 || nums[mid - 1] < target)
            {
                return mid;
            }
            else
            {
                r = mid + 1;
            }
        }
        else
        {
            l = mid + 1;
        }
    }

    return -1;
}

1.5 二分查找变体--查找最后一个小于等于给定值的元素


int bSearch(vector<int>& nums, int target) 
{
    int l = 0, r = nums.size() - 1;
    while (l <= r)
    {
        int mid = l + ((r-l)>>1);
        if (nums[mid] > target)
        {
            r = mid - 1;
        }
        else
        {
            if (mid == nums.size() - 1 || nums[mid + 1] > target)
            {
                return mid;
            }
            else
            {
                l = mid + 1;
            }
        }
    }

    return -1;
}

1.6

2 题目

2.1 搜索插入位置

35. 搜索插入位置

剑指 Offer II 068. 查找插入位置

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

        return l > r ? l : r;
    }
};

2.2 山峰数组的顶部

852. 山脉数组的峰顶索引

剑指 Offer II 069. 山峰数组的顶部

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        int l = 1, r = arr.size() - 2;
        while (l <= r)
        {
            int mid = l + ((r-l)>>1);
            if (arr[mid] > arr[mid+1] && arr[mid] > arr[mid-1])
            {
                return mid;
            }
            else if (arr[mid] < arr[mid+1])
            {
                l = mid + 1;
            }
            else if (arr[mid] > arr[mid+1])
            {
                r = mid - 1;
            }
        }

        return -1;
    }
};

2.3 有序数组中的单一元素

540. 有序数组中的单一元素

剑指 Offer II 070. 排序数组中只出现一次的数字

class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        //方法一:o(n)
        // int res = 0;
        // for (auto& i:nums)
        //     res ^= i;
        // return res;

        //方法二:o(logn)
        int n = nums.size();
        if (n == 1)
            return nums[0];
        return helper(nums, 0, n-1);
    }

    int helper(vector<int>& nums, int left, int right)
    {
        if (left <= right)
        {
            int m = left + ((right - left) >> 1);
            if ((m == 0 && nums[m] != nums[m+1]) || 
                (m == nums.size()-1 && nums[m] != nums[m-1]) ||
                (m+1 < nums.size() && m-1 >= 0 && nums[m] != nums[m+1] && nums[m] != nums[m-1]))
            {
                return nums[m];
            }
            else
            {
                int l = helper(nums, left, m-1);
                if (-1 == l)
                {
                    return helper(nums, m+1, right);
                }
                else
                {
                    return l;
                }
            }
        }

        return -1;        
    }
};

2.4 按权重随机选择

528. 按权重随机选择

剑指 Offer II 071. 按权重生成随机数

//ttps://leetcode-cn.com/problems/cuyjEf/solution/li-yong-qian-zhui-he-er-fen-sou-suo-kuai-dsxm/
/*
先把权重数组中所有权重加起来得到权重之和,然后用每个权重除以权重之和,就能得到每个下标被选择的概率。
比方说权重数组为[1,2,3,4],权重之和是10,由于下标0对应的权重是1,那么选择0的概率是10%,选择下标1、2、3的概率分别是20%、30%和40%。

可以创建另一个和权重数组的长度一样的数组sums,新数组的第i个数值sum[i]是权重数组中前i个数字之和,
有了这个数组sums就能很方便有根据等概率随机生成的数字p按照权重比例选择下标。

比方说,累加权重数组[1,2,3,4]中的权重得到的数组sums为[1,3,6,10]。有了这个累加权重的数组之后,
如果0到9之间的随机数p<1,那么选择0;
如果1<=p<3,那么选择1;
如果3<=p<6,那么选择2;
如果6<=p<10,那么选择3;

也就是说随机生成p之后,先顺序扫描累加权重数组sums找到第一个大于p的值,然后选择它对应的下标
*/
class Solution {
public:
    vector<int> data;
    int sum;
    Solution(vector<int>& w) {
        sum = 0;
        for(auto& v:w)
        {
            sum += v;
            data.push_back(sum);
        }
    }
    
    int pickIndex() {
        int target = rand() % sum;
        int l = 0, r = data.size()-1;
        //找到第一个大于 target 的值
        while(l <= r)
        {
            int mid = l + ((r - l) >> 1);
            if(data[mid] > target) 
            {
                if (mid == 0 || data[mid - 1] <= target) 
                {
                    return mid;
                }
                r = mid - 1;        
            }
            else 
            {
                l = mid + 1;
            }
        }

        return -1;
    }
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(w);
 * int param_1 = obj->pickIndex();
 */

2.5 求平方根

剑指 Offer II 072. 求平方根

69. x 的平方根 

//https://leetcode-cn.com/problems/sqrtx/solution/acm-xuan-shou-tu-jie-leetcode-sqrtx-by-r-p8fx/
class Solution {
public:
    int mySqrt(int x) {
        int l = 1, r = x, res = 0;
        while (l <= r)
        {
            int m = l + ((r - l) >> 1);
            // if (m * m <= x) 当m比较大时会溢出
            if (m <= x/m)
            {
                res = m;
                l = m + 1;
            }
            else
            {
                r = m - 1;
            }
        }

        return res;
    }
};

2.6 狒狒吃香蕉

剑指 Offer II 073. 狒狒吃香蕉

875. 爱吃香蕉的珂珂

class Solution {
public:
    int minEatingSpeed(vector<int>& piles, int H) {
        int lo = 1, hi = *max_element(piles.begin(), piles.end());
        while (lo < hi) 
        {
            int mi = lo + (hi - lo) / 2;
            if (!possible(piles, H, mi))
                lo = mi + 1;
            else
                hi = mi;
        }

        return lo;
    }

    // Can Koko eat all bananas in H hours with eating speed K?
    bool possible(vector<int>& piles, int H, int K) 
    {
        int time = 0;
        for (int p: piles)
            time += (p - 1) / K + 1;//向上取整
        return time <= H;
    }
};

2.7

2.8

2.9

2.10

2.11

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值