题目描述
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
题目给的代码:
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
bool duplicate(int numbers[], int length, int* duplication) {
}
};
很经典的一道题,但是想出一个很好的题解却很难。(记忆吧还是,我目前的水平很难理解这样的算法)
题目分析
- 鉴于形参有长度和数组,所以先做一个异常处理,如果长度小于0或者数组为空,就返回false,连查重都不用了。
- 首先我肯定是要遍历这个数组,要不然你怎么知道有没有重复的数字?而在步进到每个数组元素的时候我想着是把这个数字记录下来。
- 不过这样我需要多开一个数组,会不会空间复杂度就大了呢?
- 所以,就有了下面这个算法,利用“控制变量法”,暂时固定下标(索引index)值,然后查看下标(索引index)对应的元素值是否等于下标,
- 等于的话无可奉告,下标++,再查看下标对应的元素值是否==下标。
- 不等于,就设一个临时变量值并赋值其下标对应的元素值,然后比较临时变量值和临时变量值做下标对应的元素值是否相等,
- 如果临时变量值==临时变量值做下标对应的元素值,证明找到了数组中任意一个重复的数字,就让duplication指针(或称数组名)的duplication[0]存放临时变量值(找到的数组中任意一个重复的数字),然后返回true
- 如果临时变量值不等于临时变量值做下标对应的元素值,就直接交换下标对应的元素值和临时变量值做下标对应的元素值
本着这样一个思想。就可以写出代码:
题解代码
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
//有重复的数字返回true,无重复的数字或其他情况返回false
bool duplicate(int numbers[], int length, int* duplication) {
if(length<=0||numbers==NULL)//异常处理,注意这个NULL必须大写!!!记住!
{
return false;
}
int index=0;//下标值,初始化为0
while(index<length)//下标值做暂时固定作用并适时自增步进直到数组倒数第一个元素
//这里不能写index<=length,因为数组从0开始,如果index==length,numbers[length]不就越界了?
{
if(numbers[index]==index)//下标(索引index)对应的元素值是否等于下标
{
index++;
}
else
{
int tmp=numbers[index];//设置一个临时变量值并赋值其下标对应的元素值
if(numbers[tmp]==tmp)
//比较临时变量值和临时变量值做下标对应的元素值是否相等
//实质上numbers[tmp]和numbers[index]去比较
{
//临时变量值和临时变量值做下标对应的元素值相等
duplication[0]=tmp;
return true;
}
else//临时变量值和临时变量值做下标对应的元素值不相等
{
//交换==下标对应的元素值==和==临时变量值做下标对应的元素值
numbers[index]=numbers[tmp];
numbers[tmp]=tmp;
}
}
}
return false;//注意这里,如果数组都遍历完了没找到重复的数字,就返回false!!!!
}
};
学习一些思想和注意的地方!切记!
还是有很多值得学习的地方得,比如
①null一定写成大写,就是NULL,小写null会让编译器报错
②拿到题要观察形参表的形参存不存在接收无效实参的情况,如果存在可能接收瞎传进来的(无效的)实参的情况,必须做异常处理!
③思考循环成立条件时,如果循环体内有数组或数组元素/下标相关的代码要思考数组越界这个问题!不能顾这个不顾那个!