leetcode 劍指 Offer 49 醜數

2021-10-19 07:25:05 字數 2102 閱讀 3480

我們把只包含質因子 2、3 和 5 的數稱作醜數(ugly number)。求按從小到大的順序的第 n 個醜數。

示例:

輸入: n = 10

輸出: 12

解釋: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 個醜數。

說明:

1 是醜數。

n 不超過1690。

在已有的醜數序列上每乙個數都必須乘2, 乘3, 乘5, 這樣才不會漏掉某些醜數。假設已有的醜數序列為[1, 2, 3, ..., n1, n2], 如果單純的讓每個醜數乘2, 乘3, 乘5順序排列的話肯定會有問題,

比如如果按照這樣的順序排列下去肯定有問題[1*2, 1*3, 1*5, 2*2, 2*3, 2*5, 3*2, 3*3, 3*5, ... , n1 *2, n1 * 3, n1 * 5, n2 * 2, n3* 3, n2 * 5],因為後面乘2的資料可能會比前面乘3乘5的資料要小,那這個乘2的數應該排在他們的前面, 後面乘3的資料也可能比前面乘5的資料要小,那這個乘3的數應該排在他們的前面。

那怎麼辦呢,每個數都必須乘2, 乘3, 乘5這樣才能保證求出所有的醜數,而且還要保證醜數的順序,這個改如何同時實現呢?

通過觀察網上的各個題解,終於找到了辦法,那就是記錄每個醜數是否已經被乘2, 乘3, 乘5了, 具體的做法是

設定3個索引a, b, c,分別記錄前幾個數已經被乘2, 乘3, 乘5了,比如a表示前(a-1)個數都已經乘過一次2了,下次應該乘2的是第a個數;b表示前(b-1)個數都已經乘過一次3了,下次應該乘3的是第b個數;c表示前(c-1)個數都已經乘過一次5了,下次應該乘5的是第c個數;

對於某個狀態下的醜數序列,我們知道此時第a個數還沒有乘2(有沒有乘3或者乘5不知道), 第b個數還沒有乘3(有沒有乘2或者乘5不知道),第c個數還沒有乘5(有沒有乘2或者乘3不知道), 下乙個醜數一定是從第a醜數乘2, 第b個數乘3, 第c個數乘5中獲得,他們三者最小的那個就是下個醜數。

求得下個醜數後就得判斷這個醜數是誰,是某個數通過乘2得到的,還是某個數乘3得到的,又或是說某個數通過乘5得到的。我們可以比較一下這個新的醜數等於究竟是等於第a個醜數乘2, 還是第b個數乘3, 還是第c個數乘5, 通過比較我們肯定可以知道這個新的醜數到底是哪個數通過乘哪個數得到的。假設這個新的醜數是通過第a個數乘2得到的,說明此時第a個數已經通過乘2得到了乙個新的醜數,那下個通過乘2得到乙個新的醜數的數應該是第(a+1)個數,此時我們可以說前 a 個數都已經乘過一次2了,下次應該乘2的是第 (a+1) 個數, 所以a++;如果新的醜數是通過第b個數乘3得到的, 說明此時第 b個數已經通過乘3得到了乙個新的醜數,那下個需要通過乘3得到乙個新的醜數的數應該是第(b+1)個數,此時我們可以說前 b 個數都已經乘過一次3了,下次應該乘3的是第 (b+1) 個數, 所以 b++;同理,如果這個這個新的醜數是通過第c個數乘5得到的, 那麼c++;

但是注意,如果第a個數乘2後等於第b個數乘3,或者等於第c個數乘5, 說明這個新的醜數是有兩種或者三種方式可以得到,這時應該給得到這個新醜數的組合對應的索引都加一,比如新醜數是第a個數乘2後和第b個數乘3得到的,那麼 a 和 b都應該加一, 因為此時第a個數已經通過乘2得到了乙個新的醜數,第b個數已經通過乘3得到了乙個新的醜數, 只不過這兩個數相等而已。所以我們給計數器加一的時候不能使用 if else else if, 而應該使用if, if, if, 這樣才不會把應該加一的計數器漏掉

經過n次迴圈,就能得到第n 個醜數了。

下面是完整的**

1 class solution 

14 if(dp[i] == n3)

17 if(dp[i] == n5)

20 }

21 return dp[n-1];

22 }

23 }

leetcode執行時間為3ms > 81.70%, 空間為37.1mb > 16.14%

時間複雜度:迭代了n-1次,所以時間複雜度為o(n)

空間複雜度:需要乙個臨時陣列來存放已經產生了的醜數,所以空間複雜度為o(n)

leetcode 劍指 Offer 專題(七)

劍指 offer 專題第七部。題目 劍指 offer 66.構建乘積陣列。定義 begin v 1 i prod a k a 0 times a 1 times dots times a i 1 quad v 1 0 1 v 2 i prod a k a i 1 times dots times a...

leetcode劍指offer 字串

二叉樹,鍊錶,字串 思路 進行兩次反轉 1.對整個句子反轉 2.對句子中的單詞反轉 經過三次反 1.反轉前面的字串。2.反轉後面的字串。3.反轉整個字串 不能直接用力扣46全排列的 力扣46是無重複的數字,這個題是有重複的。正確的解法 不用not in tmp來判斷這個字母是否需要遍歷,定義乙個us...

Leetcode劍指offer系列 平衡二叉樹

傳送門 輸入一棵二叉樹的根節點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意節點的左右子樹的深度相差不超過1,那麼它就是一棵平衡二叉樹。示例 1 給定二叉樹 3,9,20,null,null,15,7 3 9 20 15 7 返回 true 示例 2 給定二叉樹 1,2,2,3,3,null,nul...