You are standing at position 0
on an infinite number line. There is a goal at position target
.
On each move, you can either go left or right. During the n-th move (starting from 1), you take n steps.
Return the minimum number of steps required to reach the destination.
Example 1:
Input: target = 3 Output: 2 Explanation: On the first move we step from 0 to 1. On the second step we step from 1 to 3.
Example 2:
Input: target = 2 Output: 3 Explanation: On the first move we step from 0 to 1. On the second move we step from 1 to -1. On the third move we step from -1 to 2.
心路历程:初看这道题,第一感觉可能的方案有三种:分支限界搜索、DP和数学规律。
先按DP的思路思考,定义d[step][target]表示第step步到达target位置所需要的最小次数(看起来很奇怪)。
那么d[step][target] = d[step - 1][target - step] + 1。此过程中target可能<0,直接取绝对值即可,因为正负仅代表方向,不影响最终结果。按此过程,step最终会等于0,即第0步能到达的位置,当然,d[0][0] = 0,d[0][N] = -1,其中N != 0,-1表示不可达。这样对于DP而言,初值与递推公式都有了,还差边界条件。可以考虑,step最大值为2*target,因为相邻两步方向相反一定会向目标前进一步。比如-1,2,-3,4,....,每2次一定会向前前进一步。
还可以进一步寻找边界,因为如果尽全力向同一个方向搜索,但仍小于target,可以直接认为不可达。例如d[step][target]中,若sum(1+2+...+step) < .target,那么d[step][target] = -1不可达。
所以对可能的step逐个验证即可。这是我的直观想法,还有数学方法,有兴趣的可以看官方答案
class Solution {
public int sum(int x){
return (1 + x) * x / 2;
}
public int reachNumber(int target) {
if(target < 0 ) target *= -1;
for(int step = 1; step <= 2*target ;step++){
int ans = recurve(step,target);
if(ans != -1) return step;
}
return 2 * target;
}
public int recurve(int step,int target){
if(target < 0 ) target *= -1;
if(step == 0){
if( target == 0) return 0;
return -1;
}
if(sum(step) < target){
return -1;
} else if(sum(step) == target){
return step;
}else{
int temp = recurve(step-1,Math.abs(target - step));
if(temp == -1) return -1;
return temp +1;
}
}
}