👋Hi~ o( ̄▽ ̄)ブ这里是猪猪程序员
👀 很高兴见到你O(∩_∩)O!
🌱 现在正在发芽中…
💞️ 博主水平有限,如果发现错误,一定要及时告知作者哦 o( ̄︶ ̄)o!感谢感谢!
📫博主的码云 gitee,平常博主写的程序代码都在里面。
⭐️这是一个新的专栏⭐️我希望自己能够坚持把《剑指offer》这本书的题目刷完。
剑指 Offer 03. 数组中重复的数字
⭐️题目来源
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:
2 或 3
限制:
2 <= n <= 100000
方法一:直接遍历(超出时间限制)
思路:将数组中的每一个数字和后面的所有数字进行比较,当发现相等时,即为结果。
int findRepeatNumber(int* nums, int numsSize){
int i,j;
for(i=0;i<numsSize;i++)
{
for(j=i+1;j<numsSize;j++)
{
if(nums[i]==nums[j])
return nums[i];
}
}
return -1;
}
方法二:排序 + 遍历(执行用时:32 ms 内存消耗:10.5 MB)
思路:排序后能保证重复的数字连续分布,这样遍历时只需要比较当前数字和下一个数字是否相同即可。
这里需要用到C语言本身的库函数qsort
–>如果不清楚的小伙伴可以看看这篇博客
int cmp(const void* a,const void* b)
{
return (*(int*)a-*(int*)b);
}
int findRepeatNumber(int* nums, int numsSize){
int i;
qsort(nums,numsSize,sizeof(int),cmp);
for(i=0;i<numsSize-1;i++)
{
if(nums[i]==nums[i+1])
return nums[i];
}
return -1;
}
方法三:哈希查找(执行用时:28 ms 内存消耗:10.4 MB)
思路:创建哈希数组(key
:数字,value
:出现次数),遍历时先检查当前索引对应的数字是否已经出现,出现则返回结果,否则更新该数字出现次数。
#define NUMS_SIZE 100000
int findRepeatNumber(int* nums, int numsSize){
int numsHash[NUMS_SIZE]={0};
for(int i=0;i<numsSize;i++)
{
if(numsHash[nums[i]]>0)
{return nums[i];}
numsHash[nums[i]]++;
}
return -1;
}
方法四:原地排序(执行用时:24 ms 内存消耗:10.3 MB)
思路:借用输入数组,将当前索引对应的数字,替换到对应的数字索引下,保证索引和数字相等。如果出现替换时,索引和数字已经相等时,说明该数字重复,返回结果。相比于思路三的优点是不需要申请额外的空间存放Hash表。执行过程如下图。
int findRepeatNumber(int* nums, int numsSize){
int temp=0,cur=0;
while(cur<numsSize)
{
if(nums[nums[cur]]!=nums[cur])
{
temp=nums[cur];
nums[cur]=nums[temp];
nums[temp]=temp;
continue;
}
if(cur==nums[cur])
{
cur++;continue;
}
return nums[cur];
}
return -1;
}
方法五:二分法(解答错误)
根据题目发现答案在[0, n-1]中, left = 0, right = n - 1, mid = (left + right) / 2,先计算整个数组中[left, mid]范围内的数的数量,如果大于
(mid - left)
,说明左侧有重复数字,right = mid,否则,left = mid,继续基于新的left, right二分。该种思路无法解决场景[0, 1, 2, 0, 4, 5, 6, 7, 8, 9]。
int Count(int* nums, int numsSize, int a, int b)
{
int cnt = 0;
int cur = 0;
while (cur < numsSize) {
if (nums[cur] >= a && nums[cur] <= b) {
cnt++;
}
cur++;
}
return cnt;
}
int findRepeatNumber(int* nums, int numsSize){
// 二分法 无法解决场景:[0, 1, 2, 0, 4, 5, 6, 7, 8, 9]
int left = 0;
int right = numsSize - 1;
int mid, count;
while (left < right - 1) {
mid = (left + right) / 2;
count = Count(nums, numsSize, left, mid);
if (count > mid + 1 - left) {
right = mid;
continue;
}
left = mid;
}
if (Count(nums, numsSize, left, left) > 1) {
return left;
}
return right;
}
总结
感觉刷题的话还是要认真把每一题搞懂才行,看着力扣的大佬们都有很多中解法,也学习到了许多,我自己昨天才刚刚学到qsort
函数,今天就用到了,加油吧!