91在线观看视频-91在线观看视频-91在线观看免费视频-91在线观看免费-欧美第二页-欧美第1页

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

常用的算法技巧總結

算法與數據結構 ? 來源:未知 ? 作者:李倩 ? 2018-11-07 10:38 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

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

1. 巧用數組下標

數組的下標是一個隱含的很有用的數組,特別是在統計一些數字,或者判斷一些整型數是否出現過的時候。例如,給你一串字母,讓你判斷這些字母出現的次數時,我們就可以把這些字母作為下標,在遍歷的時候,如果字母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[]) { int[] temp = new int[21]; for (int i = 0; i < arr.length; i++) { ? ? ? ? ? ?temp[arr[i]]++; ? ? ? ?} ? ? ? ?//順序打印 ? ? ? ?for (int i = 0; i < 21; i++) { ? ? ? ? ? ?for (int j = 0; j < temp[i]; j++) { ? ? ? ? ? ? ? ?System.out.println(i); ? ? ? ? ? ?} ? ? ? ?} ? ?}

提醒:可以左右滑動

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

2. 巧用取余

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

for (int i = 0; i < N; i++) { ? ? ? ?if (pos < N) { ? ? ? ? //沒有越界 ? ? ? ? // 使用數組arr[pos]? ? ? ? else {? ? ? ? ? pos = 0;//置為0再使用數組 ? ? ? ? ? //使用arr[pos]? ? ? ? ?}? ? ? ? pos++;? ?}

實際上我們可以通過取余的方法來簡化代碼

for (int i = 0; i < N; i++) { ? //使用數組arr[pos] ? (我們假設剛開始的時候pos < N) ? pos = (pos + 1) % N;}

3. 巧用雙指針

對于雙指針,在做關于單鏈表的題是特別有用,比如“判斷單鏈表是否有環”、“如何一次遍歷就找到鏈表中間位置節點”、“單鏈表中倒數第 k 個節點”等問題。對于這種問題,我們就可以使用雙指針了,會方便很多。我順便說下這三個問題怎么用雙指針解決吧。

例如對于第一個問題

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

對于第二個問題

一樣是設置一個快指針和慢指針。慢的一次移動一個節點,而快的兩個。在遍歷鏈表的時候,當快指針遍歷完成時,慢指針剛好達到中點。

對于第三個問題

設置兩個指針,其中一個指針先移動k個節點。之后兩個指針以相同速度移動。當那個先移動的指針遍歷完成的時候,第二個指針正好處于倒數第k個節點。

你看,采用雙指針方便多了吧。所以以后在處理與鏈表相關的一些問題的時候,可以考慮雙指針哦。

4. 巧用移位運算。

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

例如:

n / 2 等價于 n >> 1

n / 4 等價于 n >> 2

n / 8 等價于 n >> 3。

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

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

if(n % 2 == 1){ dosomething();}

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

if(n & 1 == 1){ dosomething();)

具體的一些運算技巧,還得需要你們多在實踐中嘗試著去使用,這樣用久后就會比較熟練了。

5. 設置哨兵位

在鏈表的相關問題中,我們經常會設置一個頭指針,而且這個頭指針是不存任何有效數據的,只是為了操作方便,這個頭指針我們就可以稱之為哨兵位了。

例如我們要刪除頭第一個節點是時候,如果沒有設置一個哨兵位,那么在操作上,它會與刪除第二個節點的操作有所不同。但是我們設置了哨兵,那么刪除第一個節點和刪除第二個節點那么在操作上就一樣了,不用做額外的判斷。當然,插入節點的時候也一樣。

有時候我們在操作數組的時候,也是可以設置一個哨兵的,把arr[0]作為哨兵。例如,要判斷兩個相鄰的元素是否相等時,設置了哨兵就不怕越界等問題了,可以直接arr[i] == arr[i-1]?了。不用怕i = 0時出現越界。

當然我這只是舉一個例子,具體的應用還有很多,例如插入排序,環形鏈表等。

6. 與遞歸有關的一些優化

(1).對于可以遞歸的問題考慮狀態保存

當我們使用遞歸來解決一個問題的時候,容易產生重復去算同一個子問題,這個時候我們要考慮狀態保存以防止重復計算。例如我隨便舉一個之前舉過的問題

問題:一只青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法?

這個問題用遞歸很好解決。假設 f(n) 表示n級臺階的總跳數法,則有

f(n) = f(n-1) + f(n - 2)。

遞歸的結束條件是當0 <= n <= 2時, f(n) = n。因此我們可以很容易寫出遞歸的代碼

public int f(int n) { if (n <= 2) { ? ? ? ? ? ?return n; ? ? ? ?} else { ? ? ? ? ? ?return f(n - 1) + f(n - 2); ? ? ? ?} ? ?}

不過對于可以使用遞歸解決的問題,我們一定要考慮是否有很多重復計算。顯然對于 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) { if (n <= 2) { ? ? ? ? ? ?return n; ? ? ? ?} else { ? ? ? ? ? ?if (arr[n] != 0) { ? ? ? ? ? ? ? ?return arr[n];//已經計算過,直接返回 ? ? ? ? ? ?} else { ? ? ? ? ? ? ? ?arr[n] = f(n-1) + f(n-2); ? ? ? ? ? ? ? ?return arr[n]; ? ? ? ? ? ?} ? ? ? ?} ? ?}

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

(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) { if(n <= 2) ? ? ? ? ? ?return n; ? ? ? ?int f1 = 1; ? ? ? ?int f2 = 2; ? ? ? ?int sum = 0; ? ? ? ?for (int i = 3; i <= n; i++) { ? ? ? ? ? ?sum = f1 + f2; ? ? ? ? ? ?f1 = f2; ? ? ? ? ? ?f2 = sum; ? ? ? ?} ? ? ? ?return sum; ? ?}

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

總結一下

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

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

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

今天就先講到這里,之后有時間再來多謝一些其他的。如果覺得不錯,不妨點個贊。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 算法
    +關注

    關注

    23

    文章

    4710

    瀏覽量

    95405
  • 代碼
    +關注

    關注

    30

    文章

    4900

    瀏覽量

    70758

原文標題:一些常用的算法技巧總結

文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數據結構】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    干貨總結:室內定位技術的3大常用算法

    的定位模式。室內定位種類雖然 多 ,但是 室內定位 算法很多都是通用的,總結起來有下面 3 種常用算法。 一、 近鄰法 最簡單的方式,直接選定那個信號強度最大的 AP 的位置,定位結
    的頭像 發表于 07-27 10:50 ?1.2w次閱讀
    干貨<b class='flag-5'>總結</b>:室內定位技術的3大<b class='flag-5'>常用</b><b class='flag-5'>算法</b>

    數字圖像基本處理算法小結

    初學圖像處理,在常用算法方面,二白實在是有些頭疼。就在昨天,親愛的小白師兄,對迷茫的二白伸出了援手,為二白送來了一大份干貨——圖像處理常用算法總結
    的頭像 發表于 01-29 14:46 ?1404次閱讀

    吳鑒鷹總結的單片機常用算法

    本帖最后由 吳鑒鷹 于 2014-9-28 13:32 編輯 吳鑒鷹總結的單片機常用算法QQ群1號:332164870【1000人群】(已滿)QQ群2號:194314772【1000人群
    發表于 05-27 08:26

    單片機C語言常用算法PDF下載

    灰常好哈···值得擁有{:5:}資深工程師總結的單片機C語言常用算法.pdf 2015-7-25 13:57 上傳 點擊文件名下載附件 494.04 KB, 下載次數: 12
    發表于 07-19 04:30

    單片機C語言常用算法

    【實用】資深工程師總結的單片機C語言常用算法,希望能幫助到大家!
    發表于 04-10 09:06

    嵌入式單片機程序架構之時間片輪詢法

    littlevGLhttps://mp.weixin.qq.com/s/0Ym65yv4w7UEq72QvTDK3w3、單片機常用算法總結https://mp.weixin.qq.com/s/OU...
    發表于 12-20 06:13

    常用貼片電阻阻值總結

    本人是關于常用貼片電阻阻值總結的資料,有需要的可自行下載。
    發表于 07-03 17:32 ?0次下載
    <b class='flag-5'>常用</b>貼片電阻阻值<b class='flag-5'>總結</b>

    路由器常用基礎知識總結

    路由器常用基礎知識總結路由器常用基礎知識總結路由器常用基礎知識總結
    發表于 10-30 18:08 ?0次下載

    高手總結java常用API(免費下載)

    高手總結java常用API(免費下載)。
    發表于 11-06 11:27 ?0次下載

    MATLAB常用函數總結(表格)

    MATLAB常用函數總結,MATLAB函數速查手冊,方便應用MATLAB函數
    發表于 01-21 14:31 ?0次下載

    redis常用命令總結

    本文是對redis常用命令總結
    發表于 02-09 11:25 ?1704次閱讀

    Adaboost算法總結

    集成學習的Boosting算法通過結合多個弱學習器組成強學習器,AdaBoost算法是Boosting算法中的一種,本文詳細的總結了AdaBoost
    的頭像 發表于 12-29 16:08 ?3300次閱讀
    Adaboost<b class='flag-5'>算法</b><b class='flag-5'>總結</b>

    機器學習算法常用指標匯總

    機器學習性能評價標準是模型優化的前提,在設計機器學習算法過程中,不同的問題需要用到不同的評價標準,本文對機器學習算法常用指標進行了總結
    的頭像 發表于 02-13 15:09 ?5519次閱讀
    機器學習<b class='flag-5'>算法</b><b class='flag-5'>常用</b>指標匯總

    vc++-CDC常用函數總結

    vc++-CDC常用函數總結(電源技術論壇)-該文檔為vc++-CDC常用函數總結講解文檔,是一份還算不錯的參考文檔,感興趣的可以下載看看,,,,,,,,,,,,,,,,,
    發表于 09-27 15:40 ?2次下載
    vc++-CDC<b class='flag-5'>常用</b>函數<b class='flag-5'>總結</b>

    圖像處理常用算法總結

    同圖像灰度不同,邊界處一般會有明顯的邊緣,利用此特征可以分割圖像。需要說明的是:邊緣和物體間的邊界并不等同,邊緣指的是圖像中像素的值有突變的地方,而物體間的邊界指的是現實場景中的存在于物體之間的邊界。有可能有邊緣的地方并非邊界,也有可能邊界的地方并無邊緣,因為現實世界中的物體是三維的,而圖像只具有二維信息,從三維到二維的投影成像不可避免的會丟失一部分信息;另外,成像過程中的光照和噪聲也是不可避免的重要因素。正是因為這些原因,基于邊緣的圖像分割仍然是當前圖像研究中的世界級難題,目前研究者正在試圖在邊緣提取中加入高層的語義信息。
    的頭像 發表于 04-27 11:10 ?1500次閱讀
    圖像處理<b class='flag-5'>常用</b><b class='flag-5'>算法</b><b class='flag-5'>總結</b>
    主站蜘蛛池模板: 四虎在线观看免费永久 | 亚洲一级毛片免费看 | 在线电影你懂得 | 在线观看视频你懂的 | 国产午夜a理论毛片在线影院 | 国产精品国产三级在线高清观看 | 久久青草精品免费资源站 | 污污视频在线免费看 | 午夜福免费福利在线观看 | 韩国三级床戏合集 | 国产激爽大片在线播放 | 狠狠色狠狠色综合日日小蛇 | 六月激情网| 国产老头和美女在线观看 | 狼人激情网 | 欧美在线91| 美女午夜 | 婷婷射| 污夜影院 | 亚洲成网站www久久九 | 亚洲国产精品久久婷婷 | 日韩在线天堂免费观看 | 欧美最猛黑人xxxx黑人猛交69 | 欧美在线区 | 男人j桶女人j免费视频 | 免费操人视频 | 成人中文字幕一区二区三区 | 亚洲国产日韩欧美在线as乱码 | 久久综合97色综合网 | 干干干操操操 | 麦克斯奥特曼在线观看 | 国产精品大片天天看片 | 亚洲黄色一区二区 | 极品色天使在线婷婷天堂亚洲 | 热re66久久精品国产99热 | 无毒三级 | 天天操夜夜干 | 日本三级香港三级人妇99视 | 男生女生靠逼视频 | 亚洲在成人网在线看 | 免费在线视频观看 |