数组中重复的数字
题目描述
思路
set集合
set集合是不允许有重复元素的,根据这个特点可以实现去重、判定重复
构建索引字典
字典
暂时理解为和map是一个东西,都是构建key与value的一一对应关系
本题中元素种类少于数组容量,所以是肯定可以构建出索引与容量的一一对应关系的,这是一种模式
而构建方法可以采用原地交换的方式,没完成索引构建就一直在原地交换,直到完成或遇见重复元素为止。
代码实现
set集合
class Solution {
public int findRepeatNumber(int[] nums) {
HashSet hashSet=new HashSet();
for(int num:nums){
if(!hashSet.add(num)){
return num;
}
}
return -1;
}
}
构建索引字典
class Solution {
public int findRepeatNumber(int[] nums) {
int i=0;
while(i<nums.length){
if(nums[i]==i){
i++;
continue;
}
//以当前元素值为下标的元素的值与之相等,则判定为重复
if(nums[i]==nums[nums[i]]){
return nums[i];
}
//交换元素,知道构建出下标与元素值的索引关系或找到两个相同的元素为止
int tmp=nums[i];
nums[i]=nums[tmp];
//注意nums[i]已经变化了
nums[tmp]=tmp;
}
return -1;
}
}
复杂度分析
时间复杂度
set集合为O(n),哈希表的插入和读取都是O(1),O(n)源于遍历
构建索引字典为O(n),不是很能理解
空间复杂度
set集合为O(n),哈希表占用
构建索引字典为O(1)
反思不足
思路
只能想到用暴力循环的方式,想不到可以用set集合
对set集合的应用场景不熟悉
对字典用于判断重复这一用法不熟悉
审题
没有意识到范围在n-1意味着本题是必定有不重复元素的
java se
HashSet类的不熟悉
- set集合都不允许重复元素
- add()如果添加失败会返回false
在排序数组中查找数字
题目描述
思路
二分查找寻边界
有序数组的元素查找肯定是优先考虑二分法
边界怎么找呢?
找左边界,要让right指针指向比目标数小的数,所以无论大于等于都要让right指向mid-1
找右边界,要让left指向比目标数大的数,所以小于和等于都要让left指向mid+1
因为在一连串等于判定中移动指针的不同,导致了能够求出两边边界
算法优化
转化成两次求右边界,以减少代码冗余
我们注意到最后减了1,所以我们可以找到第一个目标数的索引,然后找到右边界相减即可,第一个目标数的索引可以转化为刚好比他小1的数的右边界
转化成左边界亦可,一样的道理
代码实现
class Solution {
public int search(int[] nums, int target) {
int left=0,right=nums.length-1;
int mid=left+(right-left)/2;
//找左边界
while(left<=right){
if(nums[mid]>=target){
right=mid-1;
}else{
left=mid+1;
}
mid=left+(right-left)/2;
}
int leftIndex=right;
left=0;
right=nums.length-1;
mid=left+(right-left)/2;
//找右边界
while(left<=right){
if(nums[mid]<=target){
left=mid+1;
}else{
right=mid-1;
}
mid=left+(right-left)/2;
}
int rightIndex=left;
return rightIndex-leftIndex-1;
}
}
优化版
class Solution {
public int search(int[] nums, int target) {
return getRightIndex(nums,target)-getRightIndex(nums,target-1);
}
public int getRightIndex(int [] nums,int target){
int left=0,right=nums.length-1;
int mid=left+(right-left)/2;
while(left<=right){
if(nums[mid]<=target){
left=mid+1;
}else{
right=mid-1;
}
mid=left+(right-left)/2;
}
return left;
}
}
复杂度分析
时间复杂度
O(log2n),二分查找的复杂度
空间复杂度
O(1)
反思不足
思路
最开始是想到了用二分查找,但是想到的是找目标值,然后向左右遍历计数,这种虽然比直接遍历可能要好,但如果全是同一个数的话最坏仍是O(n)
刚开始并不是很理解找左右边界的算法
0-n-1中缺失的数字
题目描述
思路
二分法
有序数组优先考虑二分查找,只要mid索引对应的值等于mid,则一定在mid右边,否则在mid左边,根据这个关系使用二分查找
代码实现
class Solution {
public int missingNumber(int[] nums) {
int left=0,right=nums.length-1,mid=left+(right-left)/2;
while(left<=right){
if(nums[mid]==mid){
left=mid+1;
mid=left+(right-left)/2;
}else{
right=mid-1;
mid=left+(right-left)/2;
}
}
return left;
}
}
复杂度分析
时间复杂度
O(log2n),二分查找的复杂度
空间复杂度
O(1)
反思不足
思路
注意到数与索引的关系,这是有序数组,在缺少数之前,数与索引是一一对应的。于是可以根据这个遍历数组找到缺失数
想到了二分这个方向,但一开始没想到怎么用
后来发现了其中的关系,只要mid索引对应的值等于mid,则一定在mid右边,否则在mid左边,但是还是做复杂了,在进行的过程中会自动完成寻找第一个不等的索引,而不需要自己多此一举去判断。原因在于对其执行过程的细节没理解清楚,建议下次模拟一边大致过程。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?