287. 寻找重复数
这个题说简单就简单在可以直接用set去重,但是空间复杂度是O(n);
代码:
public int findDuplicate(int[] nums) {
Set<Integer> set = new HashSet<Integer>();
for(Integer x : nums){
if(set.contains(x)){
return x;
}
set.add(x);
}
return -1;
}
但是题目要求是空间复杂度是O(1)
二分法:
对于 230724 二分查找的补充
public static int findDuplicate(int[] nums) {
int len = nums.length; // n +1 = len n = len -1;
int left = 0;
int right = len - 1;
//实则是二分查找[1...n] 这个区间
// 这里不是左闭右开,只是循环可以继续的条件,为什么不需要继续搜索,
// 原因就是如果最后left == right了,当前这个left或者right就一定是重复的那个元素
while (left < right) {
int mid = (left + right) / 2;
// 统计大于mid的个数
int count = 0;
for (int x : nums) {
if (x <= mid) {
count++;
}
}
if (count > mid) {
//下一次搜索区间为[left ,mid]
right = mid;
} else {
//下一次搜索区间为[mid+1,right]
left = mid + 1;
}
}
return left;
}
参考:
算法不好玩
8-9 「力扣」第 287 题:寻找重复数_哔哩哔哩_bilibili
关于左闭右闭,左闭右开的理解
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
//这里 相等是因为 left==right的时候,还需要再进行一次循环,目的就是要不漏下数组里的数,全部比较到。
while (left <= right){
int mid = left + (right-left)/2;
if (nums[mid] > target){
right = mid-1;
}else if (nums[mid] < target){
left = mid+1;
}else {
return mid;
}
}
//如果找不到,返回-1
return -1;
}
41. 缺失的第一个正数
不难,就是O(1) 的空间复杂度有点难。
哈希法:
时间复杂度O(n),空间复杂地O(n)
**巧妙点:**只需要循环查找到 len 就可以轻松查找到。
public int firstMissingPositive(int[] nums) {
int len = nums.length;
Set<Integer> set = new HashSet<>() ;
for(int x : nums){
set.add(x);
}
//这里巧妙在只需要搜索到len 就可以了。
//[1,2,0] 这种情况 就可以保证 i= 3;
//其他一般情况就基本都可以满足了
for(int i = 1;i<=len;i++){
if(!set.contains(i)){
return i;
}
}
// [1,2,3] 这种情况 可以保证 i = 4;
return len+1;
}
原地哈希
空间复杂度O(1);
public static int firstMissingPositive(int[] nums) {
int len = nums.length;
// 先原地哈希一下, 俗称找家 。家要满足 nums[i] = i+1; 也就是 下标为0 的放 数字 1
for(int i = 0;i<len;i++){
// nums[i] > 0 为了避免 nums[0-1] = nums[-1] 造成的索引越界
// nums[i] <=len [7,8,9,11,12] 这种情况没办法找到家,就不用动。
// 我们要做的就是让能回家的回家,然后从1 开始看谁没回家,就是第一个正整数
while(nums[i] > 0 && nums[i] <= len && nums[nums[i]-1] != nums[i]){
int temp = nums[i];
nums[i] = nums[temp-1];
nums[temp-1] = temp;
}
}
// 看看谁没回到家
for(int i =0;i<len;i++){
if(nums[i]!=i+1){
return i+1;
}
}
// 都回家了,那就是长度+1 个
return len+1;
}
原地哈希额外:
剑指 Offer 03. 数组中重复的数字
public int findRepeatNumber(int[] nums) {
int len = nums.length;
for(int i =0;i<len;i++){
while(nums[i]!=i){
// 判断家是不是被人占领了。
if(nums[nums[i]]==nums[i]){
return nums[i];
}
// 这个家没人,就交换,去入住
int temp = nums[i];
nums[i] = nums[temp];
nums[temp]= temp;
}
}
return -1;
}
没人,就交换,去入住
int temp = nums[i];
nums[i] = nums[temp];
nums[temp]= temp;
}
}
return -1;
}