不同算法复杂度的对比

我们知道,不同算法在复杂度上有很大的差异,本次我们通过一道题目来体现这一点。
题目链接:189. 轮转数组 - 力扣(LeetCode)

本题的意思比较明确,旨在让我们把一个整数数组中的后k个元素拿出并放在首位

例如我们现在有一个数组【2,3,4,5,6,7】,其中k为4。按照题目的描述我们需要将后4个元素拿出并放在首位,也就是说排序之后数组应该是【4,5,6,7,2,3】。

下面我们来分析如何用代码实现这个问题:

首先我们很容易想到让后面的数组的值与前面数组的值不断交换,从而实现“轮换数组”的目的。

代码如下:

void rotate(int* nums, int numsSize, int k) 
{
    while(k--)
    {
      int end=nums[numsSize-1];
      for(int i=numsSize-1;i>0;i--)  
      {
        nums[i]=nums[i-1];
      }
      nums[0]=end;
    }
}

这里我们采用for循环的方法不断的将后面的数组元素替代前面的元素。在一次循环中,最后一个元素不断地与前面的数组元素进行交换,直至本次循环中最后一个数组元素代替了首元素,标志着本次循环结束。

为了防止这个程序进入死循环,我们让每次循环之后的k都减少一次,直至k的值变为0,所有循环结束。

这种算法乍看之下非常简短,但是他的时间复杂度很大,运行起来非常耗时。不难看出他的时间复杂度为O(N²)。

所以我们需要另辟蹊径去找寻别的解法。

在学习数组的时候,我们学过一种方法叫做冒泡排序。在冒泡排序中我们引入了一个临时变量,在这里我们也可以引入一个临时数组,我们将需要轮换的元素存入新的临时数组中。后将剩下的元素移到新数组中。

代码如下:

void rotate(int* nums, int numsSize, int k) 
{
   int arr0[numsSize];
   for(int i=0;i<numsSize;++i)
   {
    arr0[(i+k)%numsSize]=nums[i];
   }
   for(int i=0;i<numsSize;++i)
   {
    nums[i]=arr0[i];
   }
}

这种算法的时间复杂度为O(N),相比第一种解法缩短了一部分运行时间,但是还是不够简短。

除了上述两种方法,我们还可以定义一个reverse函数用于交换数组。reverse函数的功能类似于冒泡排序的交换数组。

代码如下:

void reverse(int* nums,int begin,int end)
{
    while(begin<end){
        int tmp = nums[begin];
        nums[begin] = nums[end];
        nums[end] = tmp;

        begin++;
        end--;
    }
}
void rotate(int* nums, int numsSize, int k)
{
    k = k%numsSize;
    reverse(nums,0,numsSize-k-1);
    reverse(nums,numsSize-k,numsSize-1);
    reverse(nums,0,numsSize-1);
}

这个代码极大的缩短了运行所需时间,时间复杂度为O(1)。

三种方法比较下来,运行代码所需的时间大小关系为1>2>3;从时间复杂度的角度来看,自然是第三种算法最优。

在比较算法的优劣情况时,我们要结合时间复杂度与空间复杂度两方面去比较。但是现在随着科技的发展,空间复杂度对于算法的影响已经不大,主要需要考虑时间复杂度的因素。

本次文章就到这里结束了,谢谢大家观看。如有不足,欢迎指出,必有所改进。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值