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

目录

  • 068. 查找插入位置

  • 069. 山峰数组的顶部

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

  • 071. 按权重生成随机数

  • 072. 求平方根

  • 073. 狒狒吃香蕉

068. 查找插入位置

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

题目:

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

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

示例:

输入: nums = [1,3,5,6], target = 5

输出: 2

提示:

  • 1 <= nums.length <= 104

  • -104 <= nums[i] <= 104

  • nums 为无重复元素的升序排列数组

  • -104 <= target <= 104

思路:

要达到O(log n)的复杂度,只能用二分算法

target 插入的位置 ans应该满足 nums[ans - 1] < target <= nums[ans]

套用二分模板,在 target <= nums[ans] 的时候记录ans

class Solution {

public:

int searchInsert(vector& nums, int target) {

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

// ans记录位置,初始值为nums.size()是为了防止 target大于数组内所有值

int ans = nums.size();

while(left <= right) {

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

// nums[ans - 1] < target <= nums[ans],所以小于等于且ans记录位置

if(target <= nums[mid]) {

ans = mid;

right = mid - 1;

}else {

left = mid + 1;

}

}

return ans;

}

};

069. 山峰数组的顶部

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

题目:

符合下列属性的数组 arr 称为 山峰数组(山脉数组) :

  • arr.length >= 3
  • 存在 i(0 < i < arr.length - 1)使得:
*   `arr[0] < arr[1] < ... arr[i-1] < arr[i]`
*   `arr[i] > arr[i+1] > ... > arr[arr.length - 1]`

给定由整数组成的山峰数组 arr ,返回任何满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i ,即山峰顶部。

示例:

输入:arr = [1,3,5,4,2]

输出:2

提示:

  • 3 <= arr.length <= 104

  • 0 <= arr[i] <= 106

  • 题目数据保证 arr 是一个山脉数组

思路:

二分查找

arr[mid] < arr[mid + 1] 时:表示此时在答案左边

arr[mid] >= arr[mid + 1]时:表示此事在答案右边且可能是答案,用ans记录

class Solution {

public:

int peakIndexInMountainArray(vector& arr) {

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

int ans = 0;

while(left <= right) {

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) 函数。

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

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

示例:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

独家面经总结,超级精彩

本人面试腾讯,阿里,百度等企业总结下来的面试经历,都是真实的,分享给大家!

image

image

image

image

Java面试准备

准确的说这里又分为两部分:

  1. Java刷题
  2. 算法刷题

Java刷题:此份文档详细记录了千道面试题与详解;

image

image

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
" alt=“img” style=“zoom: 33%;” />

独家面经总结,超级精彩

本人面试腾讯,阿里,百度等企业总结下来的面试经历,都是真实的,分享给大家!

[外链图片转存中…(img-IHAb8byz-1713462298517)]

[外链图片转存中…(img-eMdzZiwL-1713462298519)]

[外链图片转存中…(img-eymQZfUR-1713462298520)]

[外链图片转存中…(img-k6dz5SwB-1713462298522)]

Java面试准备

准确的说这里又分为两部分:

  1. Java刷题
  2. 算法刷题

Java刷题:此份文档详细记录了千道面试题与详解;

[外链图片转存中…(img-l3I6znj4-1713462298524)]

[外链图片转存中…(img-w0pRxY1Z-1713462298525)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值