Java-數據結構-時間和空間復雜度

一、什么是時間和空間復雜度?

📚 那么在了解時間復雜度空間復雜度之前,我們先要知道為何有這兩者的概念

首先我們要先了解"算法",在之前我們學習過關于"一維前綴和與差分""二維前綴和與差分"這部分知識,而這部分知識就屬于基礎算法中的"前綴和""差分"的兩部分,也就是說它們也是算法

而除了它們以外,其實我們在之前的學習中,大部分的知識也都和算法脫不開干系,例如:"枚舉""位運算""冒泡排序""二分查找"等,只不過在當時學習時,我們主要在意的是"如何解題"并沒有深究題解的時間效率和空間效率

📕 我們先引入一個小題

有一高度10階的樓梯,每步只能上一階或二階,請問從下往上走,一共能得到多少種走法?

這題大家應該是很熟悉的,通過我們之前學習過的函數遞歸思想,腦海中的解題思路就會是:

反向思考一下,如果我們距離最后一步到達10階,就是有兩種情況"8->10 或 9->10",而"8->10"就需要我們先走到8階,相應的"9->10"就需要我們先走到9階,所以從0階走到10階的走法應該等于"0階到9階的走法+0階到8階的走法"

相應的,之前的7,8,9階也皆是如此,于是我們便能寫出遞歸函數

public static void main(String[] args) {System.out.println(climbStairs(10));}public static int climbStairs(int num){if(num == 0){return 0;}if(num == 1){return 1;}if(num == 2){return 2;}return climbStairs(num - 1) + climbStairs(num - 2);}

這就是我們之前學習過的"函數遞歸"了,這樣的方法確實能得到答案,但是讓我們現在思考一下,這個方法的效率是否夠高呢?按照我們這段代碼的思路來看,運算過程中實際上是這樣的:

隨著每多1階樓梯。我們要計算的步驟就都相應乘以2,并且大部分的數據都是重復的。如果我們輸入一個較大的數,那么這種算法的時間損耗是相當大的

所以由此看來,這個方法就不算是一個高效率的算法,而判斷算法效率如何,就需要我們所提到的"時間和空間復雜度"了。

時間復雜度和空間復雜度是用來表示一個算法的優劣程度的

二、時間復雜度

① 時間復雜度的概念

📚 時間復雜度的定義

算法的時間復雜度是一個數學函數,它能夠大致的表示出一個算法的運行時間,因為一個算法運行所消耗的時間,是不能算出精確值的,只有將代碼運行一遍,才能夠得出對應精確的時間,但是總不能將所有的算法都測試一遍,這樣太麻煩了,于是就有了時間復雜度的分析方法:算法中的基本操作執行次數,就稱為算法的時間復雜度。

② 大O漸進表示法

📚 我們先舉一個例子,試著求一下這段代碼的時間復雜度

public static int fun(int n){int a = 0;for(int i = 0;i < n;i++){a++;}return a;}

這段代碼我們可以看出,傳入n,其中基本操作執行次數就也是n,故此代碼的時間復雜度為O(n)。

📚 那么如果我們在其中摻雜了多端基本操作,使得執行次數的函數變得較為復雜呢

public static int fun(int n){int a = 0;for(int i = 0;i < n;i++){a++;}for(int i = 0;i < n;i++){for(int j = 0;j < n;j++){a++;}}a++;a++;a++;return a;}

這段代碼中的基本操作執行次數就就稍微比較多了,我們分別來看:第一段的for循環的基本操作次數為n,而第二段的for循環嵌套的基本操作次數為n^2,第三段的基本操作次數3,所以得到的基本操作次數為n + n^2 + 3而所謂的大O漸進法就是為了簡化此等函數式的。

③ 推導大O階方法

📕 用常數1取代運行時間中的所有加法常數。

📕 在修改后的運行次數函數中,只保留最高階項。

📕 如果最高階項存在且不是1,則去除以這個項目相乘的常數。

由于我們并不需要計算精確的執行次數,我們就可以將式子中基本操作次數占比較少的部分省略掉,所以我們該式子的時間復雜度可以簡化為O(N^2)

(注:常數階的時間復雜度是O(1),代表是常數次,不是1次,只要是常數,都用O(1)進行表示)

這里我們就可以引用一下剛剛我們所提出的經典問題"爬樓梯問題"來算一下剛剛我們那個不完美的方法的時間復雜度為多少~

我們仍然看之前的思路圖,如果要上n階樓梯,那么就要算(n-1)階,(n-2)階而得到(n-1),就要知道(n-2)階,(n-3)階分別的可能次數,所以可以得到此圖:

這像是一棵二叉樹,高度為N-1,節點個數就接近2的N-1次方,所以時間復雜度近似看成O(2^N)

📚 另外有些算法的時間復雜度存在最好、平均和最壞情況

📕 最壞情況:任意輸入規模的最大運行次數(上界)

📕 最好情況:任意輸入規模的最小運行次數(下界)

📕 常見的時間復雜度量級

常數階O(1)
對數階O(logN)
線性階O(n)
線性對數階O(nlogN)
平方階O(n^2)
立方階O(n^3)
K次方階O(n^k)
指數階O(2^n)

順便一提,一般情況下我們的電腦的單秒運算量大概為 2e8次 我們在平時刷題時也可以按照這個與時間復雜度結合,就能大致估算運行時間了~

三、空間復雜度

空間復雜度是一個函數,它能夠描述一個算法執行所需的額外存儲空間,同樣用大O漸進法表示,如O(1)、O(n)、O(n^2)等。空間復雜度能夠直接影響算法對內存資源的使用

在我們平時刷題,或者算法競賽中,題目會給出空間限制,通常以MB為單位。計算空間復雜度時,我們估算程序使用的內存,基本單位換算如下:

📕 8 b = 1 B
📕 1 KB = 1024 B
📕 1 MB = 1024 KB
📕 1 GB = 1024 MB

我們要知道,int占用4字節,long占用8字節,double占用8字節等,運算空間復雜度需要我們將代碼運行過程中所有字節相加并且轉換為MB。

📚 接下來讓我們看幾段代碼練習一下

    public static void main(String[] args) {//1int[] n = new int[10000000];//2long[][] n1 = new long[2000][3000];}

📕 一個大小為 n = 10^7 的int數組,內存消耗為:4e7字節,換算成MB為 4e7/(1024*1024) 約等于38.1MB。

📕 一個大小為 2000 * 3000 的 long 二維數組,內存消耗為:8 * 2000 * 3000字節,換算成MB為(8 * 2000 * 3000) / (1024*1024) 約等于45.78MB。

public static void main(String[] args) {int[] arr = {7,9,4,8,5,6,1,2,3};bubbleSort(arr);System.out.println(Arrays.toString(arr));}public static void bubbleSort(int[] array) {for (int end = array.length; end > 0; end--) {boolean sorted = true;for (int i = 1; i < end; i++) {if (array[i - 1] > array[i]) {int tmp = array[i];array[i] = array[i - 1];array[i - 1] = tmp;sorted = false;}}if (sorted == true) {break;}}}

📕 由于bubbleSort使用的都是常數額外空間,于是空間復雜度為O(1)

    public static void main(String[] args) {System.out.println(fun(10));}public static int fun(int n) {int num = 0;int[] m = new int[n];for(int i = 1;i <= n;i++){num++;}return num;}

📕 第一行創建了int型變量,此為O(1),而后第二行創建一個數組,這個數據占用大小為n,后續的代碼中并沒有創建新的變量,故不用看。則使用的額外空間式子為1 + n,空間復雜度為O(n)

四、優化爬樓梯問題

📚 那么經過幾道題的練習,我們再回過頭來看我們最開始舉例的"爬樓梯問題"

剛剛使用遞歸的方式求解"爬樓梯問題",我們得到的對應信息為:

時間復雜度為:O(2^n)

空間復雜度為:O(n)

我們剛剛已經意識到了,O(2^n)的時間復雜度有多么可怕,并且O(n)的空間復雜度也并不是特別優秀,那么我們應該如何對其進行優化呢?

時間復雜度太高的原因是因為我們從上而下的進行分支,而這些分支中又出現了很多的重復項,導致我們的代碼會在無用的地方浪費很長時間。而想要對從上而下的分支進行操作并且判斷是否重復,是并不容易的,那么我們不妨轉換一下思路,我們可以從底向上的,一步一步通過迭代的方式來嘗試一下

首先我們先算出從1階到10階需要走的步數

我們將其寫入表格中:

然后讓我們一步一步的觀察其中的規律:

1階2階與3階的關系:

2階3階與4階的關系:

3階4階與5階的關系:

我們可以觀察到一個現象,在每一次的迭代中,F(N)只與F(N - 1)和F(N - 2)有關,也就是說當我們想求一個狀態時,只需要保留之前的兩個狀態就足夠了,之前的數據就可以扔掉不要了。

這就是最最簡單的一個動態規劃問題~

public static int climbStairs(int num){if(num == 0){return 0;}if(num == 1){return 1;}if(num == 2){return 2;}int a = 1;int b = 2;int temp = 0;for(int i = 3;i <= num;i++){temp = a + b;a = b;b = temp;}return temp;}

一共只用了一次for循環,這段代碼的時間復雜度顯而易見是O(n),而我們只使用了兩或三個變量,則空間復雜度為O(1)~

趁熱打鐵,既然已經講了這題了,有興趣的小伙伴也可以寫一下這題~就是一樣的道理,只是多了一個(一步邁三階)的可能~實際上我們只需要多寫出一個(n == 3)的情況,以及使temp變成(a + b + c)就可以了~

面試題 08.01. 三步問題 - 力扣(LeetCode)

class Solution {public int waysToStep(int n) {if(n < 1){return 0;}//一階臺階1種走法if(n == 1){return 1;}//兩階臺階2種走法if(n == 2){return 2;}//三階臺階4種走法if(n == 3){return 4;}long a = 1;long b = 2;long c = 4;long temp = 0;//F(n) = F(n - 1) + F(n - 2) + F(n - 3);//同理,后續的迭代中F(n)也只與F(n - 1) , F(n - 2) , F(n - 3)相關:for(int i = 4;i <= n;i++){temp = a + b + c;a = b;b = c;c = temp;a = a % 1000000007;b = b % 1000000007;c = c % 1000000007;temp = temp % 1000000007;}return (int)temp;}
}

那么這次關于時間和空間復雜度的知識就為大家分享到這里啦,作者能力有限,如果有什么講的不夠清楚或者有錯的地方還請多多在評論區指出,我們下次再見咯~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64731.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64731.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64731.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

商湯C++開發面試題及參考答案

C++11 有哪些新特性? C++11 帶來了眾多令人矚目的新特性,極大地豐富和增強了這門編程語言的功能與表現力。 首先是類型推導方面,引入了auto關鍵字。通過auto,編譯器能夠自動根據初始化表達式來推導出變量的類型,這在處理復雜的模板類型或者較長的類型聲明時非常方便,能讓…

Cesium 實戰 27 - 三維視頻融合(視頻投影)

Cesium 實戰 27 - 三維視頻融合(視頻投影) 核心代碼完整代碼在線示例在 Cesium 中有幾種展示視頻的方式,比如墻體使用視頻材質,還有地面多邊形使用視頻材質,都可以實現視頻功能。 但是隨著攝像頭和無人機的流行,需要視頻和場景深度融合,簡單的實現方式則不能滿足需求。…

U盤格式化工具合集:6個免費的U盤格式化工具

在日常使用中&#xff0c;U盤可能會因為文件系統不兼容、數據損壞或使用需求發生改變而需要進行格式化。一個合適的格式化工具不僅可以清理存儲空間&#xff0c;還能解決部分存儲問題。本文為大家精選了6款免費的U盤格式化工具&#xff0c;并詳細介紹它們的功能、使用方法、優缺…

如何使用AI工具cursor(內置ChatGPT 4o+claude-3.5)

??溫馨提示&#xff1a; 禁止商業用途&#xff0c;請支持正版&#xff0c;充值使用&#xff0c;尊重知識產權&#xff01; 免責聲明&#xff1a; 1、本教程僅用于學習和研究使用&#xff0c;不得用于商業或非法行為。 2、請遵守Cursor的服務條款以及相關法律法規。 3、本…

Spring Boot的開發工具(DevTools)模塊中的熱更新特性導致的問題

問題&#xff1a; java.lang.ClassCastException: class cn.best.scholarflow.framework.system.domain.entity.SysUser cannot be cast to class cn.best.scholarflow.framework.system.domain.entity.SysUser (cn.best.scholarflow.framework.system.domain.…

異常與中斷(上)

文章目錄 一、異常與中斷的概念引入與處理流程1.1 生活中的中斷1.2 母親如何處理中斷1.3 ARM系統中異常與中斷處理流程 二、ARM架構中異常與中斷的處理2.1 處理流程2.2 cortex M3/M42.2.1 M3/M4的向量表2.2.2 M3/M4的異常/中斷處理流程 2.3 cortex A72.3.1 A7的向量表2.3.2 A7的…

Zabbix 監控平臺 添加監控目標主機

Zabbix監控平臺是一個企業級開源解決方案&#xff0c;用于分布式系統監視和網絡監視。它由Zabbix Server和可選組件Zabbix Agent組成&#xff0c;通過C/S模式&#xff08;客戶端-服務器模型&#xff09;采集數據&#xff0c;并通過B/S模式&#xff08;瀏覽器-服務器模型&#x…

游戲關卡設計的常用模式

游戲關卡分為很多種&#xff0c;但常用的有固定套路&#xff0c;分為若干種類型。 關卡是主角與怪物、敵方戰斗的場所&#xff0c;包括裝飾物、通道。 單人游戲的關卡較小&#xff0c;偏線性&#xff1b; 聯機/MMO的關卡較大&#xff0c;通道多&#xff0c;自由度高&#xf…

【容器化技術 Docker 與微服務部署】詳解

容器化技術 Docker 與微服務部署 一、容器化技術概述 &#xff08;一&#xff09;概念 容器化技術是一種操作系統級別的虛擬化方法&#xff0c;它允許將應用程序及其依賴項&#xff08;如運行時環境、系統工具、庫等&#xff09;打包成一個獨立的、可移植的單元&#xff0c;這…

TypeScript 后端開發中的熱重載編譯處理

在一些除了nest框架外的一些其他nodejs框架中沒有提供對ts編譯和熱重載&#xff0c;如果使用typescript我們需要自己進行配置。 方法一&#xff08;推薦&#xff09; 使用bun運行環境&#xff08;快&#xff09;。注&#xff1a;一些不是使用js&#xff0c;ts代碼編寫的第三方…

QT集成IntelRealSense雙目攝像頭3,3D顯示

前兩篇文章&#xff0c;介紹了如何繼承intel realsense相機和opengl。 這里介紹如何給深度數據和色彩數據一塊顯示到opengl里面。 首先&#xff0c;需要了解深度數據和彩色數據是如何存儲的。先說彩色數據。彩色圖像一般都是RGB&#xff0c;也就是每個像素有三個字節&#xf…

Postman[4] 環境設置

作用&#xff1a;不同的環境可以定義不同的參數&#xff0c;在運行請求時可以根據自己的需求選擇需要的環境 1.創建Environment 步驟&#xff1a; Environment-> ->命名->添加環境變量 2.使用Environment 步驟&#xff1a;Collection- >右上角選擇需要的環境

【合并區間】

問題 以數組 intervals 表示若干個區間的集合&#xff0c;其中單個區間為 intervals[i] [starti, endi] 。 請你合并所有重疊的區間&#xff0c;并返回 一個不重疊的區間數組&#xff0c;該數組需恰好覆蓋輸入中的所有區間 。示例 1&#xff1a; 輸入&#xff1a;intervals …

SpringBoot_第二天

SpringBoot_第二天 學習目標 Mybatis整合&數據訪問 使用SpringBoot開發企業項目時&#xff0c;持久層數據訪問是前端頁面數據展示的基礎&#xff0c;SpringBoot支持市面上常見的關系庫產品(Oracle,Mysql,SqlServer,DB2等)對應的相關持久層框架&#xff0c;當然除了對于關系…

SparseViT:基于稀疏編碼Transformer的非語義中心、參數高效的圖像篡改定位

摘要 https://arxiv.org/pdf/2412.14598 非語義特征或語義無關特征&#xff0c;與圖像上下文無關但對圖像篡改敏感&#xff0c;被認為是圖像篡改定位&#xff08;IML&#xff09;的重要證據。由于無法獲得人工標簽&#xff0c;現有工作依賴于手工方法提取非語義特征。手工非語…

Redisson 分布式鎖獲取tryLock和lock的區別

問題 boolean isLock lock.tryLock(10, 30, TimeUnit.SECONDS); boolean isLock lock.lock(30, TimeUnit.SECONDS); boolean isLock lock.lock(); 三者的區別&#xff1f;&#xff1f; 這三個方法都是用于獲取 Redisson 分布式鎖的&#xff0c;但它們在獲取鎖的方式和行為…

【git】git生成rsa公鑰的方法

git生成rsa公鑰的方法 一&#xff0c;簡介二&#xff0c;操作方法三&#xff0c;總結 一&#xff0c;簡介 在工作的過程中&#xff0c;經常需要生成rsa的密鑰&#xff0c;然后提供給別人&#xff0c;然后別人給你開通代碼下載權限。本文介紹如何在本地生成rsa的密鑰供參考。 …

Zookeeper模式安裝Kafka(含常規、容器兩種安裝方式)

一、#創作靈感# 公司使用Kafka的軟件項目較多&#xff0c;故寫技術筆記鞏固知識要點 二、軟件環境 - Kafka 3.9.0 官方下載地址&#xff1a;Kafka 3.9.0 - ZooKeeper 3.9.3 官方下載地址&#xff1a;ZooKeeper 3.9.3 - Docker Desktop 4.37 容器圖形化工具 官方下載地址…

7.傅里葉級數練習題

7.傅里葉級數練習題 設函數&#xff1a; f ( x ) { ? x , 0 ≤ x ≤ 1 2 , 2 ? 2 x , 1 2 < x < 1 , f(x) \begin{cases} -x, & 0 \leq x \leq \frac{1}{2}, \\ 2 - 2x, & \frac{1}{2} < x < 1, \end{cases} f(x){?x,2?2x,?0≤x≤21?,21?<x&…

【高項】信息系統項目管理師(二)項目管理概論

一、PMBOK的發展 項目管理知識體系&#xff08;PMBOK&#xff09;是由美國項目管理協會&#xff08;PMI&#xff09;開發的一套描述項目管理專業范圍的知識體系&#xff0c;包含了對項目管理所需的知識、技能和工具的描述。 二、項目基本要素 2.1 項目基礎 項目是為提供一項…