赞
踩
思路1:排序
1.把输入的数字从小到大排序
先将n个数排序(冒泡,选择,插入)/使用C语言库函数qsort()排序,这样数字就和数组下标相对应
2.依次判断后一个数是否等于前一个数加1
遍历数组nums,用nums[ i+1 ] - nums[ i ] 判断,等于1表示两个数相邻,等于2表示缺失了的那个数
把对应的下标 i+1 输出即可
注:用于C语言的库qsort函数时间复杂度是O(nlogn),与题目不符合,所以这里就是提供思路,不提供实现代码
思路2:和差
用0到n的代数和减去a[0]到a[n-1]的和:(0+1+2+...+n)-(a[0]+a[1]+a[2]+...+a[n-1])
直接先求0到n的累加和sum,然后遍历数组求和sumNums;
用 sum - sumNums = 消失的数字
时间复杂度:O(n) 空间复杂度:O(1)
- int missingNumber(int* nums, int numsSize)
- {
- //先求 0 - n 的所有和
- //case 一:等差数列求和
- int sum = ( (0 + numsSize)* (numsSize+1)) >>1;
- int sumNums = 0; //保存nums数组的和
- //求数组的和
- for(int i = 0;i<numsSize;i++)
- {
- sumNums += nums[i];
- }
- //差值为消失的数字
- return sum - sumNums;
- }
- int miss_Number(int* nums, int n)
- {
- int i;
- int sum = 0;
- int sumNums = 0;
- //case 二:将0到n相加
- for (i = 0;i <= numsSize;i++)
- {
- sum += i;
- }
- //将nums[0]到nums[0]相加
- for (i = 0;i < numsSize;i++)
- {
- sumNums += nums[i];
- }
- return sum - sumNums;
- }

思路3:对应数字下标
数组中的值是几就在第几个位置写下这个值
建立一个新数组,将n+1个数依次与数组中的数进行对应,剩下的即为缺失的。
时间复杂度:O(n) 空间复杂度:O(n)
思路4:
给定一个值x=0(0与任何数异或等于任何数本身)
令x与0到n的所有数进行异或
令x与nums[0]到nums[n]每个值进行异或
最后x就是那个缺失数
注:异或的特点就是相同的数,无论怎么排序,异或结果都一样(即满足交换律)
例:
1^2^1^2^3=3
1^3^2^2^1=3
时间复杂度:O(n) 空间复杂度:O(1)
代码实现:
- int missingNumber(int* nums, int numsSize)
- {
- //先异或0-numsSize的所有数字
- int x = 0;
- for(int i = 0 ;i<=numsSize;i++)
- {
- x ^= i;
- }
- //再异或nums数组所有的值
- for(int i = 0;i <numsSize;i++)
- {
- x ^= nums[i];
- }
- //最后的结果就是消失的数字
- return x;
- }

进阶:
尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
你可以使用空间复杂度为 O(1) 的 1️⃣原地 算法解决这个问题吗?
1️⃣注:原地的意思是不开辟额外的空间
思路1:暴力求解,旋转k次
时间复杂度:O(N*k) 空间复杂度:O(1)
- void rotate(int* nums, int numsSize, int k)
- {
- for (int i = 0; i<k; i++)
- {
- int previous = nums[numsSize - 1];
- for (int j = 0; j<numsSize; j++)
- {
- int temp = nums[j];
- nums[j] = previous;
- previous = temp;
- }
- }
-
- }
思路2:开辟数组(额外空间)法(本质:以空间换时间)
开辟一个新的动态数组,将尾端往前K个位置开始,将原数组中的元素拷贝到新数组中,在将前半部分拷贝过去,这样就完成了数组的旋转,最后只需将内容拷贝回原数组;
时间复杂度:O(N) 空间复杂度:O(N)
思路3:巧妙逆置
思路:将长度为numsize数组分为两部分,一部分为[0,numsize-k-1],另一部分为[k,numsize-1],分别进行转置,得到数组再全部进行转置即可巧妙得到题目要求的
图释:
时间复杂度: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 numsize,int k)
- {
- if(k>=numsize)
- {
- k%=numsize;
- }//k==numsize,相当于不旋转,结果即本身;k>numsize时,相当于旋转numsize-k
- Reverse(nums,0,numsize-k-1);//对前n-k个刷逆置
- Reverse(nums,numsize-k,numsize-1);//对后k个数逆置
- Reverse(nums,0,numsize-1);//整体逆置
- }

总结:一道题有多种思路,我们不用都实现。只需要分析出每种思路的复杂度,选择复杂度最优的思路实现即可。这便是复杂度在实际中的意义
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。