空间复杂度

leetcode 26 – 删除排序数组中的重复项
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

if(nums.length < 1) return 0;
    	  int i = 0;
    	  for(int j=1; j<nums.length; j++) {
    		  if(!(nums[i] == nums[j])) {
    			  nums[i+1] = nums[j];
    			  i++;
    		  }
    	  }
 return i+1;

复杂度也叫渐进复杂度,包括时间复杂度和空间复杂度,用来分析算法执行效率与数据规模之间的增长关系,可以粗略地表示,越高阶复杂度的算法,执行效率越低。

空间复杂度: 全称是 渐进空间复杂度,表示算法的存储空间与数据规模之间的增长关系。
时间复杂度: 全称是 渐进时间复杂度,表示算法的执行时间与数据规模之间的增长关系。

1、空间复杂度

一个程序的空间复杂度是指运行完一个程序所需内存的大小。
利用程序的空间复杂度,可以对程序的运行所需的内存有个预先估计。

程序执行时所需存储空间包括以下两部分:

  • 固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括指令空间(即代码空间)、数据空间(常量、简单变量)等所占的空间。这部分属于静态空间。

  • 可变空间。这部分空间主要包括动态分配的空间,以及递归栈所需的空间等。这部分的空间大小与算法有关。

我们在写代码时,完全可以用空间来换取时间,比如字典树、哈希等都是这个原理。HashMap.get()、put()都是O(1)的时间复杂度。

空间复杂度为O(1):有的算法只需要占用少量的临时工作单元,而且不随问题规模的大小而改变,我们称这种算法是“就地”执行的,是节省存储的算法,空间复杂度为O(1)。

空间复杂度为O(n):有的算法需要占用的临时工作单元与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元,例如快速排序和归并排序算法就属于这种情况。

常见的空间复杂度就是O(1)、O(n)、O(n^2),像是O(logn)、O(nlogn)对数阶的复杂度平时都用不到,而且空间复杂度分析比时间复杂度分析要简单很多。

(1)空间复杂度为:O(1)

int i = 1;
int j = 2;
++i;
j++;
int m = i + j;

代码中的i、j、m所分配的空间都不随着处理数据量变化,因此它的空间复杂度S(n) = O(1)

(2)空间复杂度:O(n)

void print(int n) {
  int i = 0;
  int[] a = new int[n];
  for (i; i <n; ++i) {
    a[i] = i * i;
  }
}

第三行new了一个数组,这个数组占用的大小为n,虽然后面有循环,但是没有再分配新的空间,因此空间复杂度S(n) = O(n)。

2、时间复杂度

(1)T(n) = O(2n+2) (看不懂没关系,后面有解释) 时间复杂度:O(n)

int cal(int n) {
   int sum = 0;
   int i = 1;
   for (; i <= n; ++i) {
     sum = sum + i;
   }
   return sum;
 }

假设每行代码的执行时间都是一样的,为unit_time单位时间。

第 2、3 行代码分别需要== 1 个 unit_time== 的执行时间,第 4、5 行都运行了 n 遍,所以需要 2n*unit_time 的执行时间,所以这段代码总的执行时间就是== (2n+2)*unit_time==。可以看出来,所有代码的执行时间 T(n) 与每行代码的执行次数成正比。

(2)T(n) = O(2n2+ 2n + 3) 时间复杂度:O(n^2)

int cal(int n) {
   int sum = 0;
   int i = 1;
   int j = 1;
   for (; i <= n; ++i) {
     j = 1;
     for (; j <= n; ++j) {
       sum = sum +  i * j;
     }
   }
 }

第 2、3、4 行代码,每行都需要 1 个 unit_time 的执行时间,第 5、6 行代码循环执行了 n 遍,需要 2n * unit_time 的执行时间,第 7、8 行代码循环执行了 n2遍,所以需要 2n2 * unit_time 的执行时间。所以,整段代码总的执行时间 T(n) = (2n2+ 2n + 3)*unit_time。

规律:所有代码的执行时间T(n)与每行代码的执行次数成正比
把规律总结成一个公式: T(n) = O(f(n))
其中,f(n)表示每行代码执行的次数总和,因为是一个公式,所以用f(n)来表示; O表示代码的执行时间T(n)与f(n)表达式成正比。

上面是大O时间复杂度的由来和表示方法,但是分析代码的时间复杂度,一般有三种方式:(1)只关注循环执行次数最多的一段代码;(2)总的时间复杂度就等于量级最大的那段代码的时间复杂度;(3)嵌套代码的复杂度等于嵌套内外代码复杂度的乘积。

几种常见的时间复杂度实例
1、常量阶 O(1)O(1)O(1)
2、对数阶 O(logn)O(logn)O(logn)
3、线性阶 O(n)O(n)O(n)
4、线性对数阶 O(nlogn)O(nlogn)O(nlogn)
5、平方阶 O(n2)、立方阶 O(n3)……k 次方阶 O(nk)
6、指数阶 O(2n)
7、阶乘阶 O(n!)

(1)O(1)

int a = 1;
int b = 2;
int c = 3;

一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)。
(2)O(logn)、O(nlogn)

 i=1;
 while (i <= n)  {
   i = i * 2;
 }

执行次数为log2n,所以,这段代码的时间复杂度为O(log2n)

 i=1;
 while (i <= n)  {
   i = i * 3;
 }

执行次数为log3n,所以,这段代码的时间复杂度为O(log3n)
实际上,不管是以2为底、以3为底还是以10为底,我们可以把所有对数阶的时间复杂度都记为O(logn),忽略对数的底。

for(m = 1; m < n; m++) {
    i = 1;
    while(i < n) {
        i = i * 2;
    }
}

上述的时间复杂度为O(nlogn)

(3)O(m+n)、O(m*n)
代码的复杂度由两个数据的规模来决定

int cal(int m, int n) {
  int sum_1 = 0;
  int i = 1;
  for (; i < m; ++i) {
    sum_1 = sum_1 + i;
  }
 
  int sum_2 = 0;
  int j = 1;
  for (; j < n; ++j) {
    sum_2 = sum_2 + j;
  }
 
  return sum_1 + sum_2;
}

代码中,m和n表示两个数据规模,我们无法事先评估m和n谁的量级大,所以上面代码的时间复杂度就是O(m+n)。

(4)O(n)

for(i=1; i<=n; i++) {
   j = i;
   j++;
}

(5)O(n^2)

for(x=1; i <= n; x++){
   for(i = 1; i <= n; i++) {
       j = i;
       j++;
    }
}

二分查找的时间复杂度:logn
https://www.cnblogs.com/yellowgg/p/11272908.html

参考:
https://juejin.cn/post/6844904167824162823
https://juejin.cn/post/6844904087876534280

算法的复杂度包括时间复杂度和空间复杂度。时间复杂度是用来评估算法运行时间的指标,主要关注算法的执行步骤和操作次数。常见的时间复杂度有最好时间复杂度、最坏时间复杂度、平均时间复杂度和均摊时间复杂度。一般情况下,我们主要关注最坏时间复杂度。 空间复杂度是用来评估算法所需的额外空间的指标,主要关注算法在执行过程中所占用的内存空间大小。空间复杂度的计算通常是指算法实际占用的额外空间与问题规模之间的关系。常见的空间复杂度表示为S(n)=O(f(n)),其中n为问题规模,f(n)表示算法所需的额外空间。 因此,评价一个算法的效率主要是看它的时间复杂度和空间复杂度情况。时间复杂度描述了算法执行所需的时间资源,而空间复杂度描述了算法执行所需的空间资源。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [时间复杂度与空间复杂度解析](https://blog.csdn.net/qq_43558142/article/details/88082705)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [算法的时间复杂度和空间复杂度](https://blog.csdn.net/ChineseSoftware/article/details/122573570)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值