题目一
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
独立思考:哈希法
首先想到用长度为n的辅助数组的方法,时间空间复杂度都是O(n),代码如下:
// 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) {
//空指针检测
if (numbers == NULL || duplication == NULL)
return false;
//异常输入检测
for(int i = 0; i < length;i++){
if(numbers[i] < 0 || numbers[i] >= length)
return false;
}
//哈希数组初始化
int* numBin = new int[length];
for(int i = 0; i < length;i++){
numBin[i] = 0;
}
//*duplication = -1;
for(int i = 0; i < length; i++){
if(numBin[numbers[i]] != 0){
*duplication = numbers[i];
return true;
}
else
numBin[numbers[i]]++;
}
return false;
}
写后反思:
卡点:
- 传地址进函数如何修改数值;
- cout从右向左,cout << duplicate(nums, 5, &duplication) << duplication;会出错
- 哈希数组必须初始化,不能存在侥幸心理
- 提交的时候,记得带上辅助函数
特殊输入:
- 空指针
- 输入包含0~n-1之外的数
- 参数length<=0
优化思路:
如果是对空间进一步的优化,可以考虑在原数组上进行更改,
void tempInt(int* num1, int* num2){
int temp = *num1;
*num1 = *num2;
*num2 = temp;
return;
}
bool duplicate(int numbers[], int length, int* duplication) {
//空指针检测
if (numbers == NULL || duplication == NULL || length <= 0)
return false;
//异常输入检测
for(int i = 0; i < length;i++){
if(numbers[i] < 0 || numbers[i] >= length)
return false;
}
for(int i = 0; i < length; ){
if(numbers[i] != i){
if(numbers[i] == numbers[numbers[i]]){
*duplication = numbers[i];
return true;
}
else
tempInt(&numbers[i], &numbers[numbers[i]]);
}
else{
i++;
}
}
}
注意这题交换两个数字的时候,要用函数,如果用下述代码会出错!!!原因是nums[i]的值被改变了
int temp = nums[i];
nums[i] = nums[nums[i]];
nums[nums[i]] = temp;
题目二(不能修改数组)
独立思考:同上
书上思路:时间换空间(空间效率优先)考察二分查找
bool duplicate(int numbers[], int length, int* duplication) {
//空指针检测
if (numbers == NULL || duplication == NULL || length <= 0)
return false;
//异常输入检测
for(int i = 0; i < length;i++){
if(numbers[i] < 1 || numbers[i] >= length)
return false;
}
int min = 1, max = length - 1;
while(min < max){
int mid = (min + max) / 2;
cout<<min<<" "<<mid<<" "<<max<<endl;
int lnum = 0, rnum = 0;
for(int i = 0; i < length; i++){
if(numbers[i] >= min && numbers[i] <= mid)
lnum++;
if(numbers[i] <= max && numbers[i] > mid)
rnum++;
}
if(lnum > (mid - min + 1))
max = mid;
else
min = mid + 1; //注意这里一定+1
}
*duplication = min;
return true;
}
区间怎么体现在代码上?用min mid max即可
二分查找的mid设置,必须缩小空间
for里面的两个区间限定,条件要写全,不要忘记min,max的约束