劍指Offer算法題解10-19

10、動(dòng)態(tài)規(guī)劃系列

10.1 斐波那契數(shù)列??馬上解題

題目描述

求斐波那契數(shù)列的第 n 項(xiàng),n <= 39。

解題思路

(1)使用遞歸求解,會(huì)重復(fù)計(jì)算一些子問(wèn)題。例如,計(jì)算 f(4) 需要計(jì)算 f(3) 和 f(2),計(jì)算 f(3) 需要計(jì)算 f(2) 和 f(1),可以看到 f(2) 被重復(fù)計(jì)算了。

(2)使用動(dòng)態(tài)規(guī)劃,遞歸是將一個(gè)問(wèn)題劃分成多個(gè)子問(wèn)題求解,動(dòng)態(tài)規(guī)劃也是如此,但是動(dòng)態(tài)規(guī)劃會(huì)把子問(wèn)題的解緩存起來(lái),從而避免重復(fù)求解子問(wèn)題。

代碼

(1)遞歸解題略

(2)動(dòng)態(tài)規(guī)劃解題

常規(guī)解法

由于當(dāng)前項(xiàng)的值只和前兩項(xiàng)有關(guān),所以只需要保存前兩項(xiàng)的值即可,這樣就把空間復(fù)雜度由O(N)控制在O(1)。

10.2 矩形覆蓋??馬上解題

題目描述

我們可以用 2*1 的小矩形橫著或者豎著去覆蓋更大的矩形。請(qǐng)問(wèn)用 n 個(gè) 2*1 的小矩形無(wú)重疊地覆蓋一個(gè) 2*n 的大矩形,總共有多少種方法?

解題思路

當(dāng) n 為 1 時(shí),只有一種覆蓋方法:

當(dāng) n 為 2 時(shí),有兩種覆蓋方法:

要覆蓋 2*n 的大矩形,可以先覆蓋 2*1 的矩形,再覆蓋 2*(n-1) 的矩形;或者先覆蓋 2*2 的矩形,再覆蓋 2*(n-2) 的矩形。而覆蓋 2*(n-1) 和 2*(n-2) 的矩形可以看成子問(wèn)題。該問(wèn)題的遞推公式如下:

代碼:


10.3 跳臺(tái)階??馬上解題

題目描述

一只青蛙一次可以跳上 1 級(jí)臺(tái)階,也可以跳上 2 級(jí)。求該青蛙跳上一個(gè) n 級(jí)的臺(tái)階總共有多少種跳法。

解題思路

當(dāng) n = 1 時(shí),只有一種跳法:

當(dāng) n = 2 時(shí),有兩種跳法:

跳 n 階臺(tái)階,可以先跳 1 階臺(tái)階,再跳 n-1 階臺(tái)階;或者先跳 2 階臺(tái)階,再跳 n-2 階臺(tái)階。而 n-1 和 n-2 階臺(tái)階的跳法可以看成子問(wèn)題,該問(wèn)題的遞推公式為:

代碼

10.4 變態(tài)跳臺(tái)階??馬上解題

題目描述

一只青蛙一次可以跳上 1 級(jí)臺(tái)階,也可以跳上 2 級(jí)... 它也可以跳上 n 級(jí)。求該青蛙跳上一個(gè) n 級(jí)的臺(tái)階總共有多少種跳法。

解題思路

跳上 n-1 級(jí)臺(tái)階,可以從 n-2 級(jí)跳 1 級(jí)上去,也可以從 n-3 級(jí)跳 2 級(jí)上去...,那么

f(n-1) = f(n-2) + f(n-3) + ... + f(0)

同樣,跳上 n 級(jí)臺(tái)階,可以從 n-1 級(jí)跳 1 級(jí)上去,也可以從 n-2 級(jí)跳 2 級(jí)上去... ,那么

f(n) = f(n-1) + f(n-2) + ... + f(0)

代碼

11. 旋轉(zhuǎn)數(shù)組的最小數(shù)字??馬上解題

題目描述

把一個(gè)數(shù)組最開(kāi)始的若干個(gè)元素搬到數(shù)組的末尾,我們稱(chēng)之為數(shù)組的旋轉(zhuǎn)。輸入一個(gè)非遞減排序的數(shù)組的一個(gè)旋轉(zhuǎn),輸出旋轉(zhuǎn)數(shù)組的最小元素。

解題思路

(1)對(duì)數(shù)組排序,但是時(shí)間復(fù)雜度至少為O(logN),而且需要另外的空間O(N)。

(2)遍歷數(shù)組,時(shí)間復(fù)雜度為O(N)。

(3)將旋轉(zhuǎn)數(shù)組對(duì)半分可以得到一個(gè)包含最小元素的新旋轉(zhuǎn)數(shù)組,以及一個(gè)非遞減排序的數(shù)組。新的旋轉(zhuǎn)數(shù)組的數(shù)組元素是原數(shù)組的一半,從而將問(wèn)題規(guī)模減少了一半,這種折半性質(zhì)的算法的時(shí)間復(fù)雜度為 O(logN)(為了方便,這里將 log2N 寫(xiě)為 logN)。

通過(guò)修改二分查找算法進(jìn)行求解(l 代表 low,m 代表 mid,h 代表 high):當(dāng) nums[m] <= nums[h] 時(shí),表示 [m, h] 區(qū)間內(nèi)的數(shù)組是非遞減數(shù)組,[l, m] 區(qū)間內(nèi)的數(shù)組是旋轉(zhuǎn)數(shù)組,此時(shí)令 h = m;否則 [m + 1, h] 區(qū)間內(nèi)的數(shù)組是旋轉(zhuǎn)數(shù)組,令 l = m + 1。

代碼

(1)(2)省略

(3)二分法

針對(duì)數(shù)組元素不重復(fù)的數(shù)組
針對(duì)元素可以重復(fù)的數(shù)組

12、矩陣中的路徑??馬上解題

題目描述

判斷在一個(gè)矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個(gè)格子開(kāi)始,每一步可以在矩陣中向上下左右移動(dòng)一個(gè)格子。如果一條路徑經(jīng)過(guò)了矩陣中的某一個(gè)格子,則該路徑不能再進(jìn)入該格子。

例如下面的矩陣包含了一條 bfce 路徑。

解題思路

使用回溯法(backtracking)進(jìn)行求解,它是一種暴力搜索方法,通過(guò)搜索所有可能的結(jié)果來(lái)求解問(wèn)題?;厮莘ㄔ谝淮嗡阉鹘Y(jié)束時(shí)需要進(jìn)行回溯(回退),將這一次搜索過(guò)程中設(shè)置的狀態(tài)進(jìn)行清除,從而開(kāi)始一次新的搜索過(guò)程。例如下圖示例中,從 f 開(kāi)始,下一步有 4 種搜索可能,如果先搜索 b,需要將 b 標(biāo)記為已經(jīng)使用,防止重復(fù)使用。在這一次搜索結(jié)束之后,需要將 b 的已經(jīng)使用狀態(tài)清除,并搜索 c。

本題的輸入是數(shù)組而不是矩陣(二維數(shù)組),因此需要先將數(shù)組轉(zhuǎn)換成矩陣。


14、剪繩子

題目描述

把一根繩子剪成多段,并且使得每段的長(zhǎng)度乘積最大。

n = 2

return 1 (2 = 1 + 1)

n = 10

return 36 (10 = 3 + 3 + 4)

解題思路

(1)貪心

盡可能多剪長(zhǎng)度為 3 的繩子,并且不允許有長(zhǎng)度為 1 的繩子出現(xiàn)。如果出現(xiàn)了,就從已經(jīng)切好長(zhǎng)度為 3 的繩子中拿出一段與長(zhǎng)度為 1 的繩子重新組合,把它們切成兩段長(zhǎng)度為 2 的繩子。

證明:當(dāng) n >= 5 時(shí),3(n - 3) - n = 2n - 9 > 0,且 2(n - 2) - n = n - 4 > 0。因此在 n >= 5 的情況下,將繩子剪成一段為 2 或者 3,得到的乘積會(huì)更大。又因?yàn)?3(n - 3) - 2(n - 2) = n - 5 >= 0,所以剪成一段長(zhǎng)度為 3 比長(zhǎng)度為 2 得到的乘積更大。

(2)動(dòng)態(tài)規(guī)劃

先從最低處開(kāi)始計(jì)算乘積并將每個(gè)數(shù)可以剪切后得到的成績(jī)最大值進(jìn)行存儲(chǔ)。當(dāng)計(jì)算后面的值的時(shí)候利用已經(jīng)存儲(chǔ)好的最大值,計(jì)算所有可能的結(jié)果并保留最大的。時(shí)間復(fù)雜度O(n*n)空間復(fù)雜度O(n)。

代碼

(1)貪心-數(shù)學(xué)總結(jié)

(2)動(dòng)態(tài)規(guī)劃

15、二進(jìn)制中1的個(gè)數(shù)? 馬上解題

題目描述

輸入一個(gè)整數(shù),輸出該數(shù)二進(jìn)制表示中 1 的個(gè)數(shù)。

解題思路

n&(n-1)

該位運(yùn)算去除 n 的位級(jí)表示中最低的那一位。

n? ? ? : 10110100

n-1? ? : 10110011

n&(n-1) : 10110000

時(shí)間復(fù)雜度:O(M),其中 M 表示 1 的個(gè)數(shù)。

代碼

當(dāng)n為正數(shù)的時(shí)候,但是當(dāng)n為負(fù)數(shù)時(shí),最終數(shù)字會(huì)變成0xFFFFFFFF,而進(jìn)入死循環(huán)

所以有變種算法,為了避免陷入死循環(huán),可以不移動(dòng)數(shù)字n,改為移動(dòng)數(shù)字1,跟n進(jìn)行比較。

還有一個(gè)就是解題思路中的辦法:

16、數(shù)字的整數(shù)次方? 馬上解題

題目描述

給定一個(gè) double 類(lèi)型的浮點(diǎn)數(shù) base 和 int 類(lèi)型的整數(shù) exponent,求 base 的 exponent 次方。

解題思路

下面的討論中 x 代表 base,n 代表 exponent。

因?yàn)?(x*x)n/2?可以通過(guò)遞歸求解,并且每次遞歸 n 都減小一半,因此整個(gè)算法的時(shí)間復(fù)雜度為 O(logN)。

代碼

17、打印從 1 到最大的 n 位數(shù)

題目描述

輸入數(shù)字 n,按順序打印出從 1 到最大的 n 位十進(jìn)制數(shù)。比如輸入 3,則打印出 1、2、3 一直到最大的 3 位數(shù)即 999。

解題思路

由于 n 可能會(huì)非常大,因此不能直接用 int 表示數(shù)字,而是用 char 數(shù)組進(jìn)行存儲(chǔ)。

使用回溯法得到所有的數(shù)。

代碼


18.1 在 O(1) 時(shí)間內(nèi)刪除鏈表節(jié)點(diǎn)

解題思路

① 如果該節(jié)點(diǎn)不是尾節(jié)點(diǎn),那么可以直接將下一個(gè)節(jié)點(diǎn)的值賦給該節(jié)點(diǎn),然后令該節(jié)點(diǎn)指向下下個(gè)節(jié)點(diǎn),再刪除下一個(gè)節(jié)點(diǎn),時(shí)間復(fù)雜度為 O(1)。

② 否則,就需要先遍歷鏈表,找到節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn),然后讓前一個(gè)節(jié)點(diǎn)指向 null,時(shí)間復(fù)雜度為 O(N)。

綜上,如果進(jìn)行 N 次操作,那么大約需要操作節(jié)點(diǎn)的次數(shù)為 N-1+N=2N-1,其中 N-1 表示 N-1 個(gè)不是尾節(jié)點(diǎn)的每個(gè)節(jié)點(diǎn)以 O(1) 的時(shí)間復(fù)雜度操作節(jié)點(diǎn)的總次數(shù),N 表示 1 個(gè)尾節(jié)點(diǎn)以 O(N) 的時(shí)間復(fù)雜度操作節(jié)點(diǎn)的總次數(shù)。(2N-1)/N ~ 2,因此該算法的平均時(shí)間復(fù)雜度為 O(1)。


18.2 刪除鏈表中重復(fù)的結(jié)點(diǎn)? 馬上解題

題目描述

代碼


19 正則表達(dá)式匹配? 馬上解題

題目描述

請(qǐng)實(shí)現(xiàn)一個(gè)函數(shù)用來(lái)匹配包括 '.' 和 '*' 的正則表達(dá)式。模式中的字符 '.' 表示任意一個(gè)字符,而 '*' 表示它前面的字符可以出現(xiàn)任意次(包含 0 次)。

在本題中,匹配是指字符串的所有字符匹配整個(gè)模式。例如,字符串 "aaa" 與模式 "a.a" 和 "ab*ac*a" 匹配,但是與 "aa.a" 和 "ab*a" 均不匹配。

解題思路

應(yīng)該注意到,'.' 是用來(lái)當(dāng)做一個(gè)任意字符,而 '*' 是用來(lái)重復(fù)前面的字符。這兩個(gè)的作用不同,不能把 '.' 的作用和 '*' 進(jìn)行類(lèi)比,從而把它當(dāng)成重復(fù)前面字符一次。

代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 2. 實(shí)現(xiàn) Singleton 3. 數(shù)組中重復(fù)的數(shù)字 4. 二維數(shù)組中的查找 5. 替換空格 6. 從尾到...
    Observer_____閱讀 3,163評(píng)論 0 1
  • 劍指offer1到10題總覽: 二維數(shù)組的查找 替換空格 從尾到頭打印鏈表 重建二叉樹(shù) 用兩個(gè)棧實(shí)現(xiàn)隊(duì)列 旋轉(zhuǎn)數(shù)組...
    藍(lán)白絳閱讀 621評(píng)論 0 1
  • 開(kāi)個(gè)新坑,準(zhǔn)備校招研發(fā)崗面試,基本的算法還是要過(guò)關(guān)的。 寫(xiě)在前面 本系列包含《劍指Offer》66道算法題,預(yù)計(jì)一...
    機(jī)鹽Johnny閱讀 5,030評(píng)論 0 12
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請(qǐng)注明出處:http://eddy.wiki/interview-code.h...
    eddy_wiki閱讀 9,449評(píng)論 0 30
  • 千百年前,韓退之寫(xiě)了一篇《馬說(shuō)》,千里馬常有,而伯樂(lè)不長(zhǎng)有,道盡了“伯樂(lè)難覓”的心酸憤慨。 千百年后,我寫(xiě)一篇“最...
    我是王嘉譯閱讀 512評(píng)論 0 1

友情鏈接更多精彩內(nèi)容