題目連結:
題目意譯:
現在有一臺壞掉的計算機,在顯示螢幕上一開始有一個整數 startValue。在一次操作中,你可以:
將螢幕上的數字乘以 2,或是
將螢幕上的數字減去 1。
給定兩整數 startValue 以及 target,回傳要在計算機上顯示 target 最少所需的操作數。
限制:
1 ≦ startValue, target ≦ 10 ^ 9
範例測資:
範例 1:
輸入: startValue = 2, target = 3
輸出: 2
解釋: 使用一次加倍的操作以及一次的減法操作 {2 -> 4 -> 3}。
範例 2:
輸入: startValue = 5, target = 8
輸出: 2
解釋: 使用一次減法以及一次加倍 {5 -> 4 -> 8}。
範例 3:
輸入: startValue = 3, target = 10
輸出: 3
解釋: 使用加倍,然後減法最後加倍 {3 -> 6 -> 5 -> 10}。
解題思維:
假設現在的數值是 X,其中 X < target 且 2X ≧ target。可以看到我們對 X 加倍之後還需要做 2X - target 次(下稱為 c 次)的減法。
當 c ≧ 2 時,實際上我們可以在將 X 加倍前先做 floor(c ÷ 2) 次減法,其中 floor() 代表下高斯函數(對於正數等價於無條件捨去)。可以看到此時會是操作數比較少的方式。
也就是說加倍後的每兩次減法,都可以換成加倍前的一次減法。而這實際上不限於 X < target 且 2X ≧ target,任何時刻的加倍都是如此。因此如果此時 floor(c ÷ 2) ≧ 2,則我們可以在變成 X「之前」的那一次加倍之前先做 floor(floor(c ÷ 2)) 次減法……以此類推。
因此減法要越早做越好,也因此代表著正面地直接試圖從 startValue 到 target 比較困難(只是寫起來比較複雜而已,讀者可以自行想一下如何正面做)。
不過此時如果我們改為從 target 到 startValue(此時加倍操作變為砍半、減法操作變為加法),則會變相對簡單。
因為此時只要我們重複以下步驟直到 target ≦ startValue 為止:
如果 target 可以被砍半,就砍半(也就是 target 此時是偶數);反之,將 target 做一次加法,target 變為 target + 1。
此時可以看到我們盡可能地把「加法」操作往後延到不能再延為止(也就是當 target 是奇數時),因此對應於原本正面操作時「減法」盡可能地早出現。
因此上述過程中的「加法」次數加上「砍半」次數,再加上最後的 startValue - target 次的「加法」便是本題的所求最少所需次數。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。