演算法技巧總結

2021-09-02 17:34:58 字數 2932 閱讀 8341

今天和大家講講,在做演算法題時常用的一些技巧。對於平時沒用過這些技巧的人,或許你可以考慮試著去看看在實踐中能否用的上這些技巧來優化問題的解。

陣列的下標是乙個隱含的很有用的陣列,特別是在統計一些數字,或者判斷一些整型數是否出現過的時候。例如,給你一串字母,讓你判斷這些字母出現的次數時,我們就可以把這些字母作為下標,在遍歷的時候,如果字母 a 遍歷到,則 arr[a]就可以加 1 了,即 arr[a]++;

通過這種巧用下標的方法,我們不需要逐個字母去判斷。

我再舉個例子:

問題:給你 n 個無序的 int 整型陣列 arr,並且這些整數的取值範圍都在 0-20 之間,要你在 o(n) 的時間複雜度中把這 n 個數按照從小到大的順序列印出來。

對於這道題,如果你是先把這 n 個數先排序,再列印,是不可能 o(n)的時間列印出來的。但是數值範圍在 0-20。我們就可以巧用陣列下標了。把對應的數值作為陣列下標,如果這個數出現過,則對應的陣列加 1。

**如下:

public void f(int arr) 

//順序列印

for (int i = 0; i < 21; i++) }}

利用陣列下標的應用還有很多,大家以後在遇到某些題的時候可以考慮是否可以巧用陣列下標來優化。

有時候我們在遍歷陣列的時候,會進行越界判斷,如果下標差不多要越界了,我們就把它置為 0 重新遍歷。特別是在一些環形的陣列中,例如用陣列實現的佇列。往往會寫出這樣的**:

for (int i = 0; i < n; i++) 

pos++;

}

實際上我們可以通過取餘的方法來簡化**

for (int i = 0; i < n; i++)
對於雙指標,在做關於單鏈表的題是特別有用,比如「判斷單鏈表是否有環」、「如何一次遍歷就找到鍊錶中間位置節點」、「單鏈表中倒數第 k 個節點」等問題。對於這種問題,我們就可以使用雙指標了,會方便很多。我順便說下這三個問題怎麼用雙指標解決吧。

例如對於第乙個問題

我們就可以設定乙個慢指標和乙個快指標來遍歷這個鍊錶。慢指標一次移動乙個節點,而快指標一次移動兩個節點,如果該鍊錶沒有環,則快指標會先遍歷完這個表,如果有環,則快指標會在第二次遍歷時和慢指標相遇。

對於第二個問題

一樣是設定乙個快指標和慢指標。慢的一次移動乙個節點,而快的兩個。在遍歷鍊錶的時候,當快指標遍歷完成時,慢指標剛好達到中點。

對於第三個問題

設定兩個指標,其中乙個指標先移動 k 個節點。之後兩個指標以相同速度移動。當那個先移動的指標遍歷完成的時候,第二個指標正好處於倒數第 k 個節點。

你看,採用雙指標方便多了吧。所以以後在處理與鍊錶相關的一些問題的時候,可以考慮雙指標哦。

有時候我們在進行除數或乘數運算的時候,例如 n / 2,n / 4, n / 8 這些運算的時候,我們就可以用移位的方法來運算了,這樣會快很多。

例如:n / 2 等價於 n >> 1

n / 4 等價於 n >> 2

n / 8 等價於 n >> 3。

這樣通過移位的運算在執行速度上是會比較快的,也可以顯的你很厲害的樣子,哈哈。

還有一些 &(與)、|(或)的運算,也可以加快運算的速度。例如判斷乙個數是否是奇數,你可能會這樣做

if(n % 2 == 1)
不過我們用與或運算的話會快很多。例如判斷是否是奇數,我們就可以把 n 和 1 相與了,如果結果為 1,則是奇數,否則就不會。即

if(n & 1 == 1) else 

}

不過對於可以使用遞迴解決的問題,我們一定要考慮是否有很多重複計算。顯然對於 f(n) = f(n-1) + f(n-2) 的遞迴,是有很多重複計算的。如

就有很多重複計算了。這個時候我們要考慮狀態儲存。例如用 hashmap 來進行儲存,當然用乙個陣列也是可以的,這個時候就像我們上面說的巧用陣列下標了。可以當 arr[n] = 0 時,表示 n 還沒計算過,當 arr[n] != 0 時,表示 f(n)已經計算過,這時就可以把計算過的值直接返回回去了。因此我們考慮用狀態儲存的做法**如下:

//陣列的大小根據具體情況來,由於 int 陣列元素的的預設值是 0

//因此我們不用初始化

int arr = new int[1000];

public int f(int n) else else }}

這樣,可以極大著提高演算法的效率。也有人把這種狀態儲存稱之為備忘錄法

(2).考慮自底向上

對於遞迴的問題,我們一般都是從上往下遞迴的,直到遞迴到最底,再一層一層著把值返回。

不過,有時候當 n 比較大的時候,例如當 n = 10000 時,那麼必須要往下遞迴 10000 層直到 n <=2 才將結果慢慢返回,如果 n 太大的話,可能棧空間會不夠用。

對於這種情況,其實我們是可以考慮自底向上的做法的。例如我知道

f(1) = 1;

f(2) = 2;

那麼我們就可以推出 f(3) = f(2) + f(1) = 3。從而可以推出 f(4),f(5)等直到 f(n)。因此,我們可以考慮使用自底向上的方法來做。

**如下:

public int f(int n) 

return sum;

}

我們也把這種自底向上的做法稱之為遞推

總結一下

當你在使用遞迴解決問題的時候,要考慮以下兩個問題

(1). 是否有狀態重複計算的,可不可以使用備忘錄法來優化。

(2). 是否可以採取遞推的方法來自底向上做,減少一味遞迴的開銷。

演算法技巧總結

1.排序對演算法效能的影響 大家都知道排序演算法,這個應該不是很難了吧,技巧在於很多時候可以利用排序演算法來提供效能,比如 例 給定乙個陣列a n 求陣列中是否存在兩個數的和等於給定值sum並輸出?這個問題很常見,解決方法有很多種,這裡我就不贅述。這裡採用雙指標遍曆法的。陣列不一定有序,我們這裡先不...

演算法競賽 目標檢測常用技巧總結

以數智重慶.全球產業賦能創新大賽為例,目標檢測的幾種常見的做題技巧如下 針對資料集進行資料提公升 a.需要對資料進行了解,比如有哪些分類,每個分類下各有什麼特點,每個分類下的尺寸是怎樣的,分布是怎樣的 長尾分布,類別不均衡 b.資料出現了什麼樣的問題,應該怎麼去解決這些問題。多樣性,長尾分布 小目標...

一些常用的演算法技巧總結

一些常用的演算法技巧總結 給定兩個字串 s 和 t 編寫乙個函式來判斷 t 是否是 s 的字母異位詞。示例 1 輸入 s anagram t nagaram 輸出 true 示例 2 輸入 s rat t car 輸出 false 說明 你可以假設字串只包含小寫字母。public boolean i...