目录
-
068. 查找插入位置
-
069. 山峰数组的顶部
-
070. 排序数组中只出现一次的数字
-
071. 按权重生成随机数
-
072. 求平方根
-
073. 狒狒吃香蕉
===========================================================================
题目:
给定一个排序的整数数组
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;
}
};
============================================================================
题目:
符合下列属性的数组
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;
}
};
==================================================================================
题目:
给定一个只包含整数的有序数组
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];
}
};
=============================================================================
题目:
给定一个正整数数组
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;
}
};
=========================================================================
题目:
给定一个非负整数
x
,计算并返回x
的平方根,即实现int sqrt(int x)
函数。
正数的平方根有两个,只输出其中的正数平方根。
如果平方根不是整数,输出只保留整数的部分,小数部分将被舍去。
示例:
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
a工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-1DF1w9ys-1715520886802)]
[外链图片转存中…(img-jsxG8bs7-1715520886803)]
[外链图片转存中…(img-ccPbwu9F-1715520886803)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!