難度中等101
在一根無限長的數軸上,你站在0
的位置。終點在target
的位置。
每次你可以選擇向左或向右移動。第 n 次移動(從 1 開始),可以走 n 步。
返回到達終點需要的最小移動次數。
示例 1:
輸入: target = 3
輸出: 2
解釋:
第一次移動,從 0 到 1 。
第二次移動,從 1 到 3 。
示例 2:
輸入: target = 2
輸出: 3
解釋:
第一次移動,從 0 到 1 。
第二次移動,從 1 到 -1 。
第三次移動,從 -1 到 2 。
注意:
target
是在[-10^9, 10^9]
範圍中的非零整數。
思維1:首先x與-x的答案是一樣的,只是在對1 2 3 ....n中的n-1個位置加正負號是完全相反的而已,因此可以統一爲正數;然後就可以採用BFS的方式搜索整個解答樹,借用BFS能夠搜索最短路徑的特點得到答案。問題:層次過深的時候會導致隊列過大,所以無論是時間還是空間複雜度都挺令人堪憂的。
思維2:純數學解法。首先我們設k是滿足下式的最小正整數:
分情況討論:
1.取等於的情況,毫無疑問,答案就是k
2.取大於的情況:我們知道當我們將一個整數x變-x並加上它的時候,我們的數會相較原來少掉2*x,所以這裏需要討論多出來的部分是奇數還是偶數的情況
A.若爲偶數,首先我們根據對k的假設可以知道:
所以必有結果:
然而在考慮k之前,我們已經考慮過所有小於k的數。設S-target=x,因爲x<k且x%2==0,所以x/2必定是整數且屬於[1,k],直接取反即可,此時只用到了k個數。
B.若爲奇數,那麼我們設多餘的部分爲x,而我們考慮的數裏包括了x-1,我們直接將x-1取反,這樣多餘的部分就只剩下1了,再來看k
1)k爲奇數,那麼通過1+k+1-(k+2)使得多餘部分爲0。
2)k爲偶數,那麼通過1+k+1得到新的多餘部分爲偶數,有下式:
當且僅當k>=2時成立,此時讓1+k/2對應的數值取反即可。[至於k=1,已經在第一種大情況下考慮過啦 ovo ]
代碼1:
class Solution {
public:
int reachNumber(int target) {
if(target<0)target=-target;
int k=0,upBound=0;
while(upBound<target){
upBound+=++k;
}
return upBound==target?k:(((upBound-target)&1)?k+1+(k&1):k);
}
};
代碼2:(使用sqrt需要處理一些邊界問題,因爲浮點強轉爲int小數會直接截斷)
class Solution {
public:
int reachNumber(int target) {
if(target<0)target=-target;
int k=sqrt(target<<1),upBound=k*(k+1)/2;
if(upBound<target){
++k;
upBound=k*(k+1)/2;
}
return upBound==target?k:(((upBound-target)&1)?k+1+(k&1):k);
}
};