Given a positive integer n and you can do operations as follow:
- If n is even, replace n with
n/2
. - If n is odd, you can replace n with either
n + 1
orn - 1
.
What is the minimum number of replacements needed for n to become 1?
Example 1:
Input: 8 Output: 3 Explanation: 8 -> 4 -> 2 -> 1
Example 2:
Input: 7 Output: 4 Explanation: 7 -> 8 -> 4 -> 2 -> 1 or 7 -> 6 -> 3 -> 2 -> 1思路:这题可以用recursion+cache也就是dp来做,但是空间超了。
public class Solution {
public int integerReplacement(int n) {
int[] dp = new int[n+1];
dp[0] = 0; dp[1] = 0;
if(dp[n] != 0) return dp[n];
if(n == 1) return 0;
if(n %2 == 0) {
dp[n] = integerReplacement(n/2)+1;
return dp[n];
}
else {
dp[n] = Math.min(integerReplacement(n-1), integerReplacement(n+1))+1;
return dp[n];
}
}
}
思路2: 正确的姿势应该是用bit位移来考虑;
这题思路就是 1. 偶数的话,直接砍半,再运算。
2. 奇数的话,分两种情况,因为我们的目的是用最少的操作,所以,尾数分01, 和11的奇数要分别考虑:01的情况,需要直接-1,11的情况用+1,变成100然后再做会快很多。但是这里有个特殊的例子3,是-1的,要特殊处理,这样运算会快。
另外,>>>和>>的区别在于,>>>是无符号位的位移,>>是有符号位的位移。
public class Solution {
public int integerReplacement(int n) {
int count = 0;
while(n != 1){
if((n & 1) == 0){
n >>>=1;
} else if( n == 3 || ((n>>>1) & 1) == 0){
n--;
} else {
n++;
}
count++;
}
return count;
}
}
用recursion来做:
public class Solution {
public int integerReplacement(int n) {
if(n<=0) return -1;
int[] res = {Integer.MAX_VALUE};
find(n, 0, res);
return res[0];
}
public int find(int n, int step, int[] res){
if(n == 1) {
res[0] = Math.min(res[0],step);
return step;
}
if(n %2 == 0){
n = n/2;
return find(n, step+1, res);
} else {
int r1 = find(n+1, step+1, res);
int r2 = find(n-1, step+1, res);
return Math.min(r1,r2);
}
}
}