题目 03.找出数组中重复的数字
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
限制:
2 <= n <= 100000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的解法:
(1)先排序
(2)相邻比较大小
(1)排序算法
尝试了c++常用的排序算法,在未测试递归的情况下,测试发现插入排序算法速度最优,在一定编译时间内通过的还有希尔排序。下面理解一下,插入排序和希尔排序。
插入排序
对于第K个元素,将该元素的值存储在零时变量中,比较第前一个元素与该元素的大小,如果大于该元素就将前一个元素往后移动一步;
比较前面第二个元素与该元素的大小,如果大于该元素就将前第二个元素往后移动一步;
重复上述过程直到找到小于等于原来第K个元素(保存在零时变量中)的位置,并将第K个元素插入到这个元素的后面。或者找不到小于等于第K个元素的位置,就将原来第K个元素插入到数组的首地址。
————————————————
版权声明:本文为CSDN博主「liqinzhe223」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/liqinzhe11/article/details/78743743
代码如下:
//插入排序 44ms
int n = nums.size();
for (int i = 1; i < n; i++)
{
int insert_num = nums[i], j;
for (j = i - 1; j >= 0; j--)
{
if (nums[j] > insert_num)
nums[j + 1] = nums[j];
else
break;
}
nums[j + 1] = insert_num; //重要,后移的关键一步,类似交换
}
将第K个元素插入到这个元素的后面,需要理解如下的中间过程。
3个数[1,3,2], 经历如上代码,依次中间过程如下:
i = 1, j = 0, insert_num = nums[1] = 3;
nums[0] < nums[1] ;
无break; j = 0 ;
nums[1] = insert_num = 3; 3个数变为[1,3,2]
i = 2, j = 1, insert_num = nums[2] = 2;
nums[1] > nums[2] ;
nums[2] = nums[1];
3个数变为[1,3,3];
i = 2 , j = 0,insert_num = nums[2] = 2;
nums[0] < nums[1] ;
break; j = 0 ;
nums[1] = insert_num = 2;
3个数变为[1,2,3]
希尔排序
希尔排序是在插入排序的基础上进行发展的,通过一个希尔增量先排序一定间隔的数据。
简单的,一个希尔增量如下:
int increment = n / 2; increment > 0; increment /= 2
简单的,将插入排序中增1的地方改为增K就行。
如下三句代码:
j = i - increment; j >= 0; j -= increment;
nums[j + increment] = nums[j];
nums[j + increment] = insert_num;
// 希尔排序 88ms
int n = nums.size();
for (int increment = n / 2; increment > 0; increment /= 2)
{
for (int i = increment; i < n; i++)
{
int insert_num = nums[i], j;
for (j = i - increment; j >= 0; j -= increment)
{
if (nums[j] > insert_num)
nums[j + increment] = nums[j];
else
break;
}
nums[j + increment] = insert_num;
}
}
所有非递归的排序算法代码如下:
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
//先排序
//相邻比较大小
//相等的数取出来,完成
//输出结果
int repeatNum = -1;
// 版权声明:本文为CSDN博主「liqinzhe223」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
// 原文链接:https://blog.csdn.net/liqinzhe11/article/details/78743743
//冒泡排序1 编译成功,超出时间限制
// int n = nums.size();
// for (int i = 0; i < n; i++)
// {
// for (int j = 0; j < n - 1 - i; j++)
// {
// if (nums[j] > nums[j+1])
// swap(nums[j], nums[j+1]);
// }
// }
//冒泡排序2 编译成功,超出时间限制
// int n = nums.size();
// bool flag;
// for (int i = 0; i < n; i++)
// {
// flag = false;
// for (int j = 0; j < n - 1 - i; j++)
// {
// if (nums[j] > nums[j+1])
// {
// swap(nums[j], nums[j+1]);
// flag = true;
// }
// }
// if (!flag)
// break;
// }
//冒泡排序3 编译成功,超出时间限制
// int n = nums.size();
// int flag = n;
// int stop_pos;
// for (int i = 0; i < n; i++)
// {
// stop_pos = flag - 1;
// flag = 0;
// for (int j = 0; j < stop_pos; j++)
// {
// if (nums[j] > nums[j+1])
// {
// swap(nums[j], nums[j+1]);
// flag = j + 1;
// }
// }
// }
//插入排序 44ms
int n = nums.size();
for (int i = 1; i < n; i++)
{
int insert_num = nums[i], j;
for (j = i - 1; j >= 0; j--)
{
if (nums[j] > insert_num)
nums[j + 1] = nums[j];
else
break;
}
nums[j + 1] = insert_num;
}
//选择排序 编译成功,超出时间限制
// int n = nums.size();
// for (int i = 0; i < n - 1; i ++)
// {
// int swap_pos = i;
// for (int j = i + 1; j < n; j++)
// {
// if (nums[swap_pos] > nums[j])
// {
// swap_pos = j;
// }
// }
// if (swap_pos != i)
// {
// swap(nums[swap_pos], nums[i]);
// }
// }
// // 希尔排序 88ms
// int n = nums.size();
// for (int increment = n / 2; increment > 0; increment /= 2)
// {
// for (int i = increment; i < n; i++)
// {
// int insert_num = nums[i], j;
// for (j = i - increment; j >= 0; j -= increment)
// {
// if (nums[j] > insert_num)
// nums[j + increment] = nums[j];
// else
// break;
// }
// nums[j + increment] = insert_num;
// }
// }
// 堆排序,leetcode编译器不支持函数定义
//改造后 编译出错 Line 1033: Char 34: runtime error: addition of unsigned offset to 0x603000000040 overflowed to 0x603000000038 (stl_vector.h)
// int n = nums.size();
// int size = n;
// while (n)
// {
// //make_heap(a, n); //每次把新的最大元素移到堆顶,也就是nums[0]
// for (int i = size - 1; i > 0; i--)
// {
// if (i % 2 && nums[i] > nums[(i - 1) / 2])//奇数
// swap(nums[i], nums[(i - 1) / 2]);
// else if (i % 2 == 0 && nums[i] > nums[(i - 2) / 2])//偶数
// swap(nums[i], nums[(i - 2) / 2]);
// }
// n--;
// size = n;
// swap(nums[0], nums[n]); //然后把当前最大移动到后面来作为排好序的元素
// }
// 归并排序 用到递归,leetcode编译器不支持函数定义,未尝试
// 快速排序 用到递归,leetcode编译器不支持函数定义,未尝试
//相邻比较
//nums[i+1],预处理超出索引问题
if(nums[n-2]==nums[n-1])
{
repeatNum = nums[n-1];
return nums[n-1];
}
//i < n-1,,预处理超出索引问题
for(int i = 0; i < n-1 ; i++)
{
if( (nums[i] == nums[i+1]))
{
repeatNum = nums[i];//相等的数取出来
return nums[i];
}
}
return repeatNum;
}
};
(2)相邻比较大小
主要是处理超出索引问题。
//相邻比较
//nums[i+1],预处理超出索引问题
if(nums[n-2]==nums[n-1])
{
repeatNum = nums[n-1];
return nums[n-1];
}
//i < n-1,,预处理超出索引问题
for(int i = 0; i < n-1 ; i++)
{
if( (nums[i] == nums[i+1]))
{
repeatNum = nums[i];//相等的数取出来
return nums[i];
}
}
参考链接:C++排序算法代码汇总