当前位置:   article > 正文

有关时间复杂度和空间复杂度的练习_常见的时间空间复杂度选择题

常见的时间空间复杂度选择题

目录

一、消失的数字

二、轮转数组

三、 单选题



一、消失的数字

数组nums包含从0n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在 O(n) 时间内完成吗?

注意:本题相对书上原题稍作改动

示例 1

输入:[3,0,1]

输出:2

示例 2

输入:[9,6,4,2,3,5,7,0,1]

输出:8

代码实现一(使用异或运算)

  1. int missingNumber(int* nums, int numsSize)
  2. {
  3. int ans = 0;
  4. for (int i = 0; i <= numsSize; ++i)
  5. {
  6. ans ^= i;
  7. }
  8. for (int i = 0; i < numsSize; ++i)
  9. {
  10. ans ^= nums[i];
  11. }
  12. return ans;
  13. }

代码实现二(使用等差数列求和公式)

  1. int missingNumber(int* nums, int numsSize)
  2. {
  3. int sum = numsSize * (numsSize + 1) / 2;
  4. for (int i = 0; i < numsSize; ++i)
  5. {
  6. sum -= nums[i];
  7. }
  8. return sum;
  9. }

以上两种算法的时间复杂度都是 O(n),空间复杂度都是 O(1)

 

二、轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1

输入: nums = [1,2,3,4,5,6,7], k = 3

输出: [5,6,7,1,2,3,4]

解释:

向右轮转 1 步: [7,1,2,3,4,5,6]

向右轮转 2 步: [6,7,1,2,3,4,5]

向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2

输入:nums = [-1,-100,3,99], k = 2

输出:[3,99,-1,-100]

解释:

向右轮转 1 步: [99,-1,-100,3]

向右轮转 2 步: [3,99,-1,-100]

提示

  • 1 <= nums.length <= 10^5

  • -2^31 <= nums[i] <= 2^31 - 1

  • 0 <= k <= 10^5

进阶

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

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

代码实现一

  1. void rotate(int* nums, int numsSize, int k)
  2. {
  3. k %= numsSize;
  4. int* tmp = (int*)malloc(sizeof(int) * k);
  5. if (NULL == tmp)
  6. {
  7. perror("malloc failed!");
  8. return;
  9. }
  10. // 首先把数组后面的 k 个元素存放到 tmp 指向的临时空间中
  11. int j = 0;
  12. for (int i = numsSize - k; i < numsSize; ++i)
  13. {
  14. tmp[j++] = nums[i];
  15. }
  16. // 然后把数组前面的 numsSize - k 个元素按从后往前的顺序依次往后移动 k 个位置
  17. for (int i = numsSize - k - 1; i >= 0; --i)
  18. {
  19. nums[i + k] = nums[i];
  20. }
  21. // 最后再将存放在临时空间中的 k 个元素放回数组中
  22. for (int i = 0; i < k; ++i)
  23. {
  24. nums[i] = tmp[i];
  25. }
  26. free(tmp);
  27. tmp = NULL;
  28. }

该算法的时间复杂度是 O(n),空间复杂度是 O(k)

代码实现二

  1. void reverse(int* nums, int left, int right)
  2. {
  3. while (left < right)
  4. {
  5. int tmp = nums[left];
  6. nums[left] = nums[right];
  7. nums[right] = tmp;
  8. ++left;
  9. --right;
  10. }
  11. }
  12. void rotate(int* nums, int numsSize, int k)
  13. {
  14. k %= numsSize;
  15. reverse(nums, 0, numsSize - k - 1);
  16. reverse(nums, numsSize - k, numsSize - 1);
  17. reverse(nums, 0, numsSize - 1);
  18. }

该算法的时间复杂度是 O(n),空间复杂度是 O(1)

分析(示例一)

  1. 1 2 3 4 | 5 6 7,即根据 k 将整数数组 nums 分为左右两个部分。

  2. 4 3 2 1 | 7 6 5,它是分别逆序左右两个部分后得到的结果。

  3. 5 6 7 | 1 2 3 4,它是整体逆序后得到的结果。

在逆序的过程中,越靠后的元素经过逆序后就会越靠前,因此整体逆序后,左右两部分的元素发生了互换,但由于之前已经分别逆序了左右两部分的元素,因此在第 3 步后,两部分的元素的顺序较一开始没有发生改变。

三、 单选题

给定一个整数 sum,从有 n 个有序元素的数组中寻找元素 a, b,使得 a + b 的结果最接近 sum,最快的平均时间复杂度是:

A、O(n)

B、O(nlogn)

C、O(n^2)

D、O(logn)

代码实现(假设数组是按非递减顺序排列)

  1. int* findClosestPair(int* nums, int numsSize, int sum, int* returnSize)
  2. {
  3. *returnSize = 2;
  4. int* ans = (int*)malloc(sizeof(int) * 2);
  5. if (NULL == ans)
  6. {
  7. perror("malloc failed!");
  8. return NULL;
  9. }
  10. int left = 0;
  11. int right = numsSize - 1;
  12. int dif = INT_MAX;
  13. while (left < right)
  14. {
  15. int res = nums[left] + nums[right] - sum;
  16. if (abs(res) < dif) // 判断是否更新误差
  17. {
  18. ans[0] = nums[left];
  19. ans[1] = nums[right];
  20. dif = abs(res);
  21. }
  22. if (res < 0) // 此时 nums[left] + nums[x] < res < 0,其中 x < right
  23. ++left;
  24. else if (res > 0) // 此时 nums[right] + nums[x] > res > 0,其中 x > left
  25. --right;
  26. else
  27. break;
  28. }
  29. return ans;
  30. }

该算法的时间复杂度为 O(n),因此正确答案是 A

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/968181
推荐阅读
相关标签
  

闽ICP备14008679号