第一题
对于该题,最能想到应该有四种方法:
1. 排序
可以将元素排序好,再遍历一遍数组看后一个是否是前一个元素的值+1,但是从对于初学者掌握的无非就是冒泡排序或者qsort
很遗憾,虽然但是,不满足题目的时间复杂为O(n),因为冒泡排序的时间复杂度为O(n^2),qsort的时间复杂度为O(nlogn)因此,因此不行
2. 映射
开辟一个数组并初始化为-1(因为有0的存在),把对应的数字放入对应的数组下标所对应的数组元素中,然后再遍历一遍数组,出现负数的那个元素则为缺少的数字
很遗憾,虽然但是,要使用数组开辟空间,空间复杂度为O(n),因此不行
3. 使用操作符 ^
使用异或操作符,利用它的两个特性,同样的数字异或以后为0,不论顺序,一个数字与0异或为本身,空间复杂度O(1),时间复杂度为O(n)
所以可以!附上代码
int missingNumber(int* nums, int numsSize) {
int i = 0;
int temp = 0;
//先和数组异或
for (i = 0; i < numsSize; i++)
{
temp ^= nums[i];
}
//再和0~n的数字异或,就得到缺少的数字
for (i = 0; i <= numsSize; i++)
{
temp ^= i;
}
return temp;
}
4. 等差数列
因为是0~n的数字,因此,这是一个等差数列,所以先把0~n的数字求和,再减去数组中的所有元素,剩下的数字即为所缺数字,时间复杂为O(n),空间复杂度为O(1),因此可行,附上代码
int missingNumber(int* nums, int numsSize) {
int i = 0;
//等差数列求和
int Sn = ((0 + (numsSize)) * (numsSize + 1)) / 2;
//减去数组中的每个值,即剩下的就是缺少值
for (i = 0; i < numsSize; i++)
{
Sn -= nums[i];
}
return Sn;
}
第二题
题目要求至少三种方法,这道题最容易能想到能想到两种,第三种不太好想到
1. 右旋k次,依次移一个
先把数组最后一个元素先给放到一个临时变量temp中,然后将数组中的元素从第一个开始依次往后赋值,最后将temp中的值赋给第一个元素,即完成了一次的右旋,右旋k次即按这个思路进行k次
这个方法的空间复杂度是O(1), 但是,时间复杂度是O(n*k),为什么是k呢?
因为这种情况最好的结果是k=1,但是最坏的结果却是要旋转n-1次(k % N = N - 1),也就是说,时间复杂度最差能到O(n^2),受k影响过大,所以用k最好
很遗憾,虽然但是,这种方法leetcode不给过,时间超出限制,时间复杂度太差!
2. 额外开数组
开过个数组,然后把k个元素放过去,很简单
很遗憾,虽然但是,空间复杂度和时间复杂度都是O(n),不满足要求!
3. 逆置三次
前N~K个元素逆置,后K个逆置,然后整体逆置
时间复杂度为O(n),空间复杂度为O(1),满足
代码如下
void reverse(int* nums, int left, int right)
{
while(left < right)
{
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
++left;
--right;
}
}
void rotate(int* nums, int numsSize, int k){
//防越界
k %= numsSize;
//前面部分逆置
reverse(nums, 0, numsSize-k-1);
//后面部分逆置
reverse(nums, numsSize-k, numsSize-1);
//全部逆置
reverse(nums, 0, numsSize-1);
}