LeetCode 剑指 Offer II 二分查找 专题总结

蜂信物联FastBee平台https://gitee.com/beecue/fastbee

阿里资料开源项目https://gitee.com/vip204888

百度低代码前端框架https://gitee.com/baidu/amis

OpenHarmony开源项目https://gitcode.com/openharmony

仓颉编程语言开放项目https://gitcode.com/Cangjie

int mid = ((right - left) >> 1) + left;

// 数组最小长度为3,不用担心越界问题

if(arr[mid] < arr[mid + 1]) {

left = mid + 1;

}else {

// arr[mid] > arr[mid + 1] 时记录

ans = mid;

right = mid - 1;

}

}

return ans;

}

};

070. 排序数组中只出现一次的数字

==================================================================================

题目:

给定一个只包含整数的有序数组 nums ,每个元素都会出现两次,唯有一个数只会出现一次,请找出这个唯一的数字。

示例:

输入: nums = [1,1,2,3,3,4,4,8,8]

输出: 2

输入: nums = [3,3,7,7,10,11,11]

输出: 10

提示:

  • 1 <= nums.length <= 105

  • 0 <= nums[i] <= 105

进阶: 采用的方案可以在 O(log n) 时间复杂度和 O(1) 空间复杂度中运行吗?

思路:

通过观察可以知道答案必然在数组下标为偶数的位置上,而且这个数组是升序的,可以使用二分查找

所以我们在查找时只需考虑偶数位,奇数跳过,知道这个即可用二分实现 O(log n) 复杂度

  • nums[mid] == nums[mid + 1] 代表这个不是答案且两个数一样,都跳过 left = mid + 2;
  • nums[mid] < nums[mid + 1] 代表这个数在答案右边也有可能是答案,ans保存

class Solution {

public:

// 注释的奇数,偶数说的是数组下标

// 思路:答案必定在偶数位上,因为相同的两个数都相邻,所以可以根据数组下标以及相邻数大小判断答案在左边还是在右边

int singleNonDuplicate(vector& nums) {

// 这样就不用担心数组越界问题了

if(nums.size() == 1)

return nums[0];

int left = 0, right = nums.size() - 1;

int ans = 0;

while(left <= right) {

int mid = ((right - left) >> 1) + left;

// 答案一定在数组下标偶数位上,所以只考虑偶数位

if(mid & 1 == 1) mid–;

if(nums[mid] == nums[mid + 1]) {

// 如果这个数不是答案,相当于他右边也不是,直接跳过

left = mid + 2;

}else {

ans = mid;

right = mid - 1;

}

}

return nums[ans];

}

};

071. 按权重生成随机数

=============================================================================

题目:

给定一个正整数数组 w ,其中 w[i] 代表下标 i 的权重(下标从 0 开始),请写一个函数 pickIndex ,它可以随机地获取下标 i,选取下标 i 的概率与 w[i] 成正比。

例如,对于 w = [1, 3],挑选下标 0 的概率为 1 / (1 + 3) = 0.25 (即,25%),而选取下标 1 的概率为 3 / (1 + 3) = 0.75(即,75%)。

也就是说,选取下标 i 的概率为 w[i] / sum(w) 。

示例:

输入:

inputs = [“Solution”,“pickIndex”,“pickIndex”,“pickIndex”,“pickIndex”,“pickIndex”]

inputs = [[[1,3]],[],[],[],[],[]]

输出:

[null,1,1,1,1,0]

解释:

Solution solution = new Solution([1, 3]);

solution.pickIndex(); // 返回 1,返回下标 1,返回该下标概率为 3/4 。

solution.pickIndex(); // 返回 1

solution.pickIndex(); // 返回 1

solution.pickIndex(); // 返回 1

solution.pickIndex(); // 返回 0,返回下标 0,返回该下标概率为 1/4 。

由于这是一个随机问题,允许多个答案,因此下列输出都可以被认为是正确的:

[null,1,1,1,1,0]

[null,1,1,1,1,1]

[null,1,1,1,0,0]

[null,1,1,1,0,1]

[null,1,0,1,0,0]

诸若此类。

提示:

  • 1 <= w.length <= 10000

  • 1 <= w[i] <= 10^5

  • pickIndex 将被调用不超过 10000

思路:

前缀和 + 二分查找

以权重数组 [1, 2, 3, 4] 为例,标 0 的概率为 10% ,下标 1 、2 、 3 的概率为 20% 、30% 和40%。先按等概率生成 1 ~ 10,则每个数字的概率的都为 10%。如果生成 1 则选择下标 0,概率为 10%;如果生成 2 或 3 则选择下标 1,概率为 20%;如果生成 4、5 或 6 则选择下标 2,概率为 30%;如果生成 7、8、9 或 10 则选择下标 3,概率为 40%。

用前缀和数组pre存储,因为pre递增,所以二分查找pre数组

答案满足:pre[mid - 1] < rand() <= pre[mid] , (mid == 0)直接返回,防止越界

class Solution {

public:

vector pre;

Solution(vector& w) {

int sum = 0;

for(int i : w) {

sum += i;

pre.push_back(sum);

}

}

int pickIndex() {

int left = 0, right = pre.size() - 1;

// 取随机数

int target = rand() % pre.back() + 1;

while(left <= right) {

int mid = ((right - left) >> 1) + left;

if(target <= pre[mid] ) {

if(mid == 0 || target > pre[mid - 1])

return mid;

right = mid - 1;

}else {

left = mid + 1;

}

}

return -1;

}

};

072. 求平方根

=========================================================================

题目:

给定一个非负整数 x ,计算并返回 x 的平方根,即实现 int sqrt(int x) 函数。

正数的平方根有两个,只输出其中的正数平方根。

如果平方根不是整数,输出只保留整数的部分,小数部分将被舍去。

示例:

输入: x = 8

输出: 2

解释: 8 的平方根是 2.82842…,由于小数部分将被舍去,所以返回 2

提示:

  • 0 <= x <= 231 - 1

思路:

二分查找

mid * mid <= x,则答案在右边或本身,ans记录

mid * mid > x,则答案在左边

mid * mid <= x 换成mid <= x / mid防止乘积过大,同时过滤0,防止除数为0

class Solution {

public:

int mySqrt(int x) {

// 防止除数为0

if(x == 0)

return 0;

int left = 1, right = x;

int ans = 0;

while(left <= right) {

int mid = ((right - left) >> 1) + left;

// 将原本的 mid * mid <= x 可能越界,所以换格式

if(mid <= x / mid) {

ans = mid;

left = mid + 1;

}else {

right = mid - 1;

}

}

return ans;

}

};

073. 狒狒吃香蕉

==========================================================================

题目:

狒狒喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。

狒狒可以决定她吃香蕉的速度 K (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 K 根。如果这堆香蕉少于 K 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉,下一个小时才会开始吃另一堆的香蕉。

狒狒喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。

返回她可以在 H 小时内吃掉所有香蕉的最小速度 KK 为整数)。

示例:

输入: piles = [3,6,7,11], H = 8

输出: 4

提示:

  • 1 <= piles.length <= 10^4

  • piles.length <= H <= 10^9

  • 1 <= piles[i] <= 10^9

思路:

速度取值[1, piles.max],因为速度至少为1,超过数组最大值也只能吃数组最大值那么多

然后对区间二分查找,check(piles, mid)函数计算mid速度所用时间

一线互联网大厂Java核心面试题库

image

正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!

提示:

  • 1 <= piles.length <= 10^4

  • piles.length <= H <= 10^9

  • 1 <= piles[i] <= 10^9

思路:

速度取值[1, piles.max],因为速度至少为1,超过数组最大值也只能吃数组最大值那么多

然后对区间二分查找,check(piles, mid)函数计算mid速度所用时间

一线互联网大厂Java核心面试题库

[外链图片转存中…(img-aDemRDPZ-1725192645028)]

正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!

  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值