Python遞歸與遞推的練習(初步了解復雜度,全排列的價值,奇妙的變換,數正方形,高塔登頂方案)

一.了解復雜度

1.1 為什么要考慮復雜度

? ? ? ? 在比賽中,編程題會有時間和空間的限制,所以我們需要根據時間復雜度和空間復雜度來判斷用什么樣的算法。

? ? ? ? 在本章中遞歸的時間復雜度比遞推慢好多所有我們在寫代碼時對遞歸和遞推的選擇中應該盡量考慮遞推。

? ? ? ? 復雜度的計算這里不做講述,入門學習只需要了解為什么要有復雜度并且可以有能力做i出判斷

1.2 常見的時間的復雜度(又快到慢)

1.2.1常數時間復雜度?O(1)

????????無論輸入規模多大,算法執行時間都是固定的。

int getFirst(int arr[], int n) {return arr[0];  // 只執行一次,與數組大小n無關
}

1.2.2?對數時間復雜度?O(log?n)

????????這個?log?log,在大多數情況下,都是以?22?為底,即?O(log?2n)O(log2?n),每一步都將問題規模縮小為原來的一部分(通常是一半)。

二分查找示例

int binarySearch(int arr[], int n, int target) {int left = 0, right = n - 1;while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] == target) return mid;else if (arr[mid] < target) left = mid + 1;else right = mid - 1;}return -1;  // 沒找到
}

? ?在這個例子中,每一步我們都將搜索范圍縮小一半,所以復雜度是O(log?n)

1.2.3 線性時間復雜度?O(n)

????????算法執行時間與輸入規模成正比。

順序查找示例

int linearSearch(int arr[], int n, int target) {for (int i = 0; i < n; i++) {if (arr[i] == target)return i;}return -1;  // 沒找到
}

這個算法最壞情況下需要遍歷整個數組,所以復雜度是O(n).

1.2.4線性對數時間復雜度?O(nlog?n)

通常出現在分治算法中,如歸并排序和快速排序。

歸并排序示例

void merge(int arr[], int left, int mid, int right) {// 合并兩個已排序的子數組// 這一步的復雜度是O(n)
}void mergeSort(int arr[], int left, int right) {if (left < right) {int mid = left + (right - left) / 2;mergeSort(arr, left, mid);        // 遞歸排序左半部分mergeSort(arr, mid + 1, right);   // 遞歸排序右半部分merge(arr, left, mid, right);     // 合并結果}
}

歸并排序的時間復雜度是O(nlog?n),因為我們將數組分成兩半(log?n層)并在每一層執行O(n)的操作。

1.2.5 平方時間復雜度?O(n2)

通常出現在嵌套循環中。

冒泡排序示例

void bubbleSort(int arr[], int n) {for (int i = 0; i < n; i++) {for (int j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {// 交換arr[j]和arr[j+1]int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}

這個算法有兩層嵌套循環,所以復雜度是O(n2)。

1.2.6 立方時間復雜度?O(n3)

通常出現在三層嵌套循環中。

Floyd算法(求所有點對之間的最短路徑)示例

void floyd(int graph[MAX][MAX], int n) {for (int k = 0; k < n; k++) {for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {if (graph[i][k] + graph[k][j] < graph[i][j])graph[i][j] = graph[i][k] + graph[k][j];}}}
}

這個算法有三層嵌套循環,所以復雜度是O(n3)。

1.2.7 指數時間復雜度?O(2n)

通常出現在需要列舉所有可能性的算法中。

遞歸求解斐波那契數列(未優化)示例

int fibonacci(int n) {if (n <= 1)return n;return fibonacci(n - 1) + fibonacci(n - 2);
}

這個未優化的算法時間復雜度是O(2n),因為對于每個n,我們需要計算兩個子問題。

1.2.8 階乘時間復雜度?O(n!)

通常出現在需要列舉全排列的算法中。

暴力求解旅行商問題示例

int tsp(int graph[MAX][MAX], int n) {// 存儲所有城市vector<int> cities;for (int i = 1; i < n; i++)cities.push_back(i);int min_path = INT_MAX;// 嘗試所有可能的城市訪問順序do {int current_path = 0;// 計算當前路徑長度int j = 0;for (int i = 0; i < cities.size(); i++) {current_path += graph[j][cities[i]];j = cities[i];}current_path += graph[j][0];  // 返回起點min_path = min(min_path, current_path);} while (next_permutation(cities.begin(), cities.end())); // 求全排列return min_path;
}

這個算法需要枚舉所有可能的城市訪問順序,時間復雜度為O(n!)。

1.3 常見的空間復雜度

1.3.1 常數空間復雜度?O(1)

算法使用的額外空間與輸入規模無關。

int findMax(int arr[], int n) {int max_val = arr[0];  // 只使用一個變量for (int i = 1; i < n; i++) {if (arr[i] > max_val)max_val = arr[i];}return max_val;
}

這個算法只使用了一個額外變量,空間復雜度是O(1)。

1.3.2 線性空間復雜度?O(n)

算法使用的額外空間與輸入規模成正比。

int[] duplicateArray(int arr[], int n) {int[] result = new int[n];  // 創建一個大小為n的新數組for (int i = 0; i < n; i++) {result[i] = arr[i];}return result;
}

這個算法創建了一個與輸入大小相同的新數組,空間復雜度是O(n)。

1.3.3 遞歸調用棧的空間復雜度(不需要太了解)

遞歸算法會使用調用棧空間,需要考慮遞歸深度。

int factorial(int n) {if (n <= 1)return 1;return n * factorial(n - 1);
}

這個遞歸算法的空間復雜度是O(n),因為遞歸深度為n。

1.3.4 平方空間復雜度?O(n2)

int[][] createMatrix(int n) {int[][] matrix = new int[n][n];  // 創建一個n×n的矩陣for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {matrix[i][j] = i * j;}}return matrix;
}

這個算法創建了一個n×n的矩陣,空間復雜度是O(n2)。

二.遞歸與遞推的比較

2.1遞歸與遞推定義比較

? ? ? ? 遞歸:是指在函數的定義中使用函數自身的方式

示例:

def factorial_recursive(n):# 基本情況if n == 0 or n == 1:return 1# 遞歸情況else:return n * factorial_recursive(n - 1)# 測試
print(factorial_recursive(5))  

? ? ? ? 遞推:?是指通過已知的初始條件,利用特定的遞推關系,逐步推導出后續的結果。遞推通常使用循環結構來實現,避免了函數的嵌套調用。

?示例:

def factorial_iterative(n):result = 1for i in range(1, n + 1):result *= ireturn result# 測試
print(factorial_iterative(5))  

?2.2 性能比較

時間復雜度

  • 遞歸:在大多數情況下,遞歸的時間復雜度與遞推相同,但由于遞歸存在函數調用的開銷,可能會導致實際運行時間更長。例如,計算斐波那契數列時,簡單的遞歸實現會有大量的重復計算,時間復雜度為?O(2n)。
def fibonacci_recursive(n):if n == 0 or n == 1:return nelse:return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)# 測試
print(fibonacci_recursive(5))  
  • 遞推:遞推的時間復雜度通常較低,因為它避免了重復計算。同樣是計算斐波那契數列,遞推實現的時間復雜度為?O(n)。
def fibonacci_iterative(n):if n == 0 or n == 1:return na, b = 0, 1for i in range(2, n + 1):a, b = b, a + breturn b# 測試
print(fibonacci_iterative(5))  

空間復雜度

  • 遞歸:遞歸會使用系統棧來保存每一層的函數調用信息,因此空間復雜度與遞歸深度成正比。在最壞情況下,遞歸的空間復雜度可能達到?O(n)。
  • 遞推:遞推通常只需要常數級的額外空間,因此空間復雜度為?O(1)。

2.3適用場景

遞歸
  • 問題可以自然地分解為規模更小的子問題,且子問題的結構與原問題相同。
  • 問題的求解過程具有明顯的遞歸性質,如樹的遍歷、圖的深度優先搜索等。
遞推
  • 問題的初始條件和遞推關系明確,且不需要使用遞歸的思想來解決。
  • 對時間和空間復雜度有較高要求,需要避免遞歸帶來的額外開銷。

三.全排列的價值

問題描述

對于一個排列?A=(a1,a2,?,an)A=(a1?,a2?,?,an?), 定義價值?cici??為?a1a1??至?ai?1ai?1??中小于?aiai??的數 的個數, 即?ci=∣{aj∣j<i,aj<ai}∣。?ci?=∣{aj?∣j<i,aj?<ai?}∣。??

定義?AA的價值為?∑i=1nci∑i=1n?ci??。

給定?n?求 1 至?n的全排列中所有排列的價值之和。

輸入格式

輸入一行包含一個整數?n。

輸出格式

輸出一行包含一個整數表示答案, 由于所有排列的價值之和可能很大, 請 輸出這個數除以 998244353 的余數。

樣例輸入 1

3

樣例輸出 1

9

樣例輸入 2

2022

樣例輸出 2

593300958

樣例說明

1 至 3 構成的所有排列的價值如下:

(1,2,3):0+1+2=3

(1,3,2):0+1+1=2

(2,1,3):0+0+2=2

(2,3,1):0+1+0=1

(3,1,2):0+0+1=1

(3,2,1):0+0+0=0

故總和為?3+2+2+1+1=9

分析:

假定4個數排序,

  1. 正排序:1,2,3,4價值和為6,反排序:4,3,2,1的價值和為0

  2. 正排序:1,3,2,4價值和為5,反排序:4,2,3,1的價值和為1

    ……

    依次推下去就會發現這種正排序和對應的反排序的價值和相加為一個定值6,所以4個數排序就是24種排序方式,12對排列式,價值和也就有12個6,總價值和就是72

所以當輸入n個數時就有n!/2?對排列式,而我們可以靠第一個正排序就能推出這個定值價值和,說白了就是0+1+2+3,就是一個簡單的等差數列求和,一對排列式的價值和就是n(n-1)/2

代碼:

a=998244353
n=int(input())
ans=n*(n-1)//2%a
for i in range(3,n+1):ans=ans*i%a
print(ans)

四.奇妙的變換

?

?

分析:?

? ? ? ? 這道題可以直接按照題意來寫,用遞歸寫比較簡單但是考慮到時間復雜度,所以可以調用sys庫里面的 sys.setrecursionlimit()來提升時間復雜度

代碼:

import sys
sys.setrecursionlimit(100000)n=int(input())
ans=0
MOD=998244353def F(x):if x>10:ans=2*x*F(x-6)else:ans=x*(x-1)return ansprint(F(n)%MOD)

?

五.數正方形

分析:

這道題本身是不難的,最重要的是需要觀察到底怎樣才能組成一個正方形 我們發現由n*n個頂點能夠組成1-n-1變長的正方形 于是我們先分別統計1-n-1的正方形個數 然后我們發現,當邊長大于2時,其內部也能組成斜的正方形 進一步觀察發現,邊長為2的內部能組成一個,為3的內部能組成2個,以此類推,我們就能計算出來總共的正方形個數了

代碼:?

n=int(input())
ans=0for i in range(1,n):if i==1:ans+=(n-i)**2else:ans+=(n-i)**2*iprint(ans%(10**9+7))

總結?

? ? ? ? 其實遞歸和遞推中有很多題可以通過找規律得出,所以大家在寫代碼時可以多多觀察題目帶入幾個數值找到規律,會對代碼有很大幫助

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

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

相關文章

解決分布式事務的方案 —— Seata

解決分布式事務的方案 —— Seata 1. 認識 Seata 解決分布式事務的方案有很多&#xff0c;但實現起來都比較復雜&#xff0c;因此我們一般會使用開源的框架來解決分布式事務問題。在眾多的開源分布式事務框架中&#xff0c;功能最完善、使用最多的就是阿里巴巴在 2019 年開源…

Antd實現上傳下載csv文件

1 上傳 解析csv文件&#xff1a; import { parse } from papaparse;export function parseCSV(file: File): Promise<string[][]> {return new Promise((resolve, reject) > {const reader new FileReader();reader.onload () > {const csvData reader.result…

Asp.net Core API 本地化

本文是一個demo&#xff0c;演示了如何根據用戶接口查詢字段(正常放header中),設置當前culture&#xff0c;并獲取當前culture的key value給用戶提示 創建Resources文件夾&#xff0c;添加以下三個文件 其中ExceptionUnuse 是一個空的類&#xff0c;供IStringLocalizer使用&a…

MambaVision:一種Mamba-Transformer混合視覺骨干網絡

摘要 我們提出了一種新型混合Mamba-Transformer主干網絡&#xff0c;稱為MambaVision&#xff0c;該網絡專為視覺應用而設計。我們的核心貢獻包括重新設計Mamba公式&#xff0c;以增強其對視覺特征的高效建模能力。此外&#xff0c;我們還對將視覺Transformer&#xff08;ViT&…

{瞎掰} 手機安裝app問題:app簽名,手機 or OS官方商店 其他非官方app源,安全防護 突破限制

以下&#xff0c;在華為安卓系統手機中&#xff0c;在安裝app過程中得到的一些可能是錯誤的經驗。 商品化 app 的收錢方式&#xff1a;通過商店來收錢&#xff0c;通過 app 本身提供的注冊碼功能來收錢&#xff0c;或是其他的收錢方式。 手機安裝 app的特點 從官方商店里安裝…

【數據庫】Data Model(數據模型)數據模型分析

理解圖片中的 Data Model&#xff08;數據模型&#xff09;是學習數據庫設計和應用程序開發的重要一步。作為初學者&#xff0c;你可以通過比喻和簡單的解釋來理解這些概念以及它們之間的聯系。以下是對圖片中數據模型的詳細分析&#xff0c;以及如何理解它們之間的關系。 1. 數…

如何管理需求變更

管理需求變更的關鍵在于 明確變更流程、跨部門協同、數據驅動反饋。其中&#xff0c;明確變更流程要求在項目初期就建立嚴格的需求變更流程和審批機制&#xff0c;確保每一次變更都有據可依&#xff1b;跨部門協同強調各部門間緊密溝通&#xff0c;整合多方意見&#xff0c;以避…

每天五分鐘深度學習PyTorch:循環神經網絡RNN的計算以及維度信息

本文重點 前面我們學習了RNN從何而來,以及它的一些優點,我們也知道了它的模型的大概情況,本文我們將學習它的計算,我們來看一下RNN模型的每一個時間步在計算什么? RNN的計算 ht-1是上一時刻的輸出,xt是本時刻的輸入,然后二者共同計算得到了ht,然后yt通過ht計算得到,…

JSP+Servlet實現對數據庫增刪改查之進階mvc架構

1.Bean層&#xff08;Model層&#xff09;? 角色&#xff1a;就像餐廳里的“菜品”。?功能&#xff1a;是純數據對象&#xff08;如Person類&#xff09;&#xff0c;封裝屬性和 getter/setter&#xff08;例如用戶名、密碼&#xff09;。?示例&#xff1a;Person類 packa…

多任務學習與持續學習微調:深入探索大型語言模型的性能與適應性

引言 大型語言模型&#xff08;LLMs&#xff09;的出現極大地推動了自然語言處理領域的發展。為了使其在各種特定任務和動態環境中表現出色&#xff0c;微調技術至關重要。本節將深入探討多任務學習&#xff08;Multi-task Learning, MTL&#xff09;和持續學習&#xff08;Co…

Ubuntu24.04 啟動后突然進入tty,無法進入圖形界面

問題描述 昨晚在編譯 Android AOSP 14 后&#xff0c;進入了登錄頁面&#xff0c;但出現了無法輸入密碼的情況&#xff0c;且無法正常關機&#xff0c;只能強制重啟。重啟后&#xff0c;系統只能進入 TTY 頁面&#xff0c;無法進入圖形界面。 問題排查 經過初步排查&#x…

圖論——廣度優先搜索實現

99. 島嶼數量 題目描述 給定一個由 1(陸地)和 0(水)組成的矩陣,你需要計算島嶼的數量。島嶼由水平方向或垂直方向上相鄰的陸地連接而成,并且四周都是水域。你可以假設矩陣外均被水包圍。 輸入描述 第一行包含兩個整數 N, M,表示矩陣的行數和列數。 后續 N 行,每行…

【sql靶場】第13、14、17關-post提交報錯注入保姆級教程

目錄 【sql靶場】第13、14、17關-post提交報錯注入保姆級教程 1.知識回顧 1.報錯注入深解 2.報錯注入格式 3.使用的函數 4.URL 5.核心組成部分 6.數據編碼規范 7.請求方法 2.第十三關 1.測試閉合 2.列數測試 3.測試回顯 4.爆出數據庫名 5.爆出表名 6.爆出字段 …

[項目]基于FreeRTOS的STM32四軸飛行器: 六.2.4g通信

基于FreeRTOS的STM32四軸飛行器: 六.2.4g通信 一.Si24Ri原理圖二.Si24R1芯片手冊解讀三.驅動函數講解五.移植2.4g通訊&#xff08;飛控部分&#xff09;六.移植2.4g通訊&#xff08;遙控部分&#xff09;七.通訊模塊的完成&#xff08;遙控部分&#xff09; 一.Si24Ri原理圖 S…

PyQt6內嵌http.server Web 和Flask Web服務器方法詳解

PyQt6 可以內嵌一個簡單的 Web 服務器。雖然 PyQt6 本身不提供直接的 Web 服務器功能&#xff0c;但可以結合 Python 的標準庫&#xff08;如 http.server&#xff09;或其他 Web 框架&#xff08;如 Flask、FastAPI 等&#xff09;來實現。 示例&#xff1a;使用 http.server…

【源碼分析】Nacos實例注冊流程分析-事件驅動框架

【踩坑記錄】 本人下載的Nacos 服務端版本是2.3.2&#xff0c;在開始進行源碼編譯便遇到問題&#xff0c;下面是各個問題記錄 源碼大量爆紅 在最開始用Idea加載Maven項目的時候&#xff0c;發現項目中大量的代碼爆紅&#xff0c;提示其類或者包不存在&#xff0c;后來結果查…

Unity物理射線濾除某層

關鍵點&#xff1a;使用LayerMask&#xff0c;針對Physics里檢測collider的射線&#xff08;raycast、OverlapSphere...&#xff09;都適用 1.使用layerMask過濾層 int ignoreLayer LayerMask.NameToLayer("IgnoreRaycast");// 獲取要忽略的層 int layerMask ~(1…

【白話神經網絡(二)】矩陣、CNN、RNN

全連接層 回顧前面學過的知識&#xff1a; 一個最簡單的神經網絡&#xff0c;就是ywxb 套上一個激活函數。 如果有多個輸入&#xff0c;那就是多個w和x 如果有多個輸出&#xff0c;那就再來一行公式&#xff0c;多一組w和b 要是神經元多了的話&#xff0c;公式密密麻麻的&…

Unity教程(二十二)技能系統 分身技能

Unity開發2D類銀河惡魔城游戲學習筆記 Unity教程&#xff08;零&#xff09;Unity和VS的使用相關內容 Unity教程&#xff08;一&#xff09;開始學習狀態機 Unity教程&#xff08;二&#xff09;角色移動的實現 Unity教程&#xff08;三&#xff09;角色跳躍的實現 Unity教程&…

深入解析Java面向對象三大特征之多態、final、抽象類與接口

面向對象編程&#xff08;OOP&#xff09;的三大核心特征為封裝、繼承、多態&#xff0c;其中多態是最具靈活性和擴展性的特性。本文將從多態的本質出發&#xff0c;結合final關鍵字、抽象類與接口的設計&#xff0c;深入探討這些概念的應用場景及其在代碼中的實現細節&#xf…