当前位置:   article > 正文

时间复杂度和空间复杂度课堂习题_计算时间复杂度跟空间复杂度例题

计算时间复杂度跟空间复杂度例题

例题1: 消失的数字

思路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)

  1. int missingNumber(int* nums, int numsSize)
  2. {
  3.     //先求 0 - n 的所有和
  4.     //case 一:等差数列求和
  5.     int sum = ( (0 + numsSize)* (numsSize+1)) >>1;
  6.     int sumNums = 0; //保存nums数组的和
  7.     //求数组的和
  8.     for(int i = 0;i<numsSize;i++)
  9.         {
  10.     sumNums += nums[i];
  11.     }
  12.     //差值为消失的数字
  13.     return sum - sumNums;
  14. }
  1. int miss_Number(int* nums, int n)
  2. {
  3. int i;
  4. int sum = 0;
  5. int sumNums = 0;
  6. //case 二:将0到n相加
  7. for (i = 0;i <= numsSize;i++)
  8. {
  9. sum += i;
  10. }
  11. //将nums[0]到nums[0]相加
  12. for (i = 0;i < numsSize;i++)
  13. {
  14. sumNums += nums[i];
  15. }
  16. return sum - sumNums;
  17. }

思路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)

代码实现:

  1. int missingNumber(int* nums, int numsSize)
  2. {
  3. //先异或0-numsSize的所有数字
  4. int x = 0;
  5. for(int i = 0 ;i<=numsSize;i++)
  6.         {
  7. x ^= i;
  8. }
  9. //再异或nums数组所有的值
  10. for(int i = 0;i <numsSize;i++)
  11.         {
  12. x ^= nums[i];
  13. }
  14. //最后的结果就是消失的数字
  15. return x;
  16. }

例题2:旋转数组

进阶:

  • 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。

  • 你可以使用空间复杂度为 O(1) 的 1️⃣原地 算法解决这个问题吗?

1️⃣注:原地的意思是不开辟额外的空间

思路1:暴力求解,旋转k次

时间复杂度:O(N*k) 空间复杂度:O(1)

  1. void rotate(int* nums, int numsSize, int k)
  2. {
  3. for (int i = 0; i<k; i++)
  4. {
  5. int previous = nums[numsSize - 1];
  6. for (int j = 0; j<numsSize; j++)
  7. {
  8. int temp = nums[j];
  9. nums[j] = previous;
  10. previous = temp;
  11. }
  12. }
  13. }

思路2:开辟数组(额外空间)法(本质:以空间换时间)

开辟一个新的动态数组,将尾端往前K个位置开始,将原数组中的元素拷贝到新数组中,在将前半部分拷贝过去,这样就完成了数组的旋转,最后只需将内容拷贝回原数组;

时间复杂度:O(N) 空间复杂度:O(N)


思路3:巧妙逆置

思路:将长度为numsize数组分为两部分,一部分为[0,numsize-k-1],另一部分为[k,numsize-1],分别进行转置,得到数组再全部进行转置即可巧妙得到题目要求的

图释:

时间复杂度:O(N) 空间复杂度:O(1)

  1. //逆置
  2. void Reverse(int *nums,int left,int right)
  3. {
  4. while(left<right)
  5.     {
  6. int temp=nums[left];
  7. nums[left]=nums[right];
  8. nums[right]=temp;
  9. left++;
  10. right--;
  11. }
  12. }
  13. void Rotate(int *nums,int numsize,int k)
  14. {
  15.     if(k>=numsize)
  16.     {
  17.     k%=numsize;
  18.     }//k==numsize,相当于不旋转,结果即本身;k>numsize时,相当于旋转numsize-k
  19. Reverse(nums,0,numsize-k-1);//对前n-k个刷逆置
  20. Reverse(nums,numsize-k,numsize-1);//对后k个数逆置
  21. Reverse(nums,0,numsize-1);//整体逆置
  22. }

总结:一道题有多种思路,我们不用都实现。只需要分析出每种思路的复杂度,选择复杂度最优的思路实现即可。这便是复杂度在实际中的意义

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号