算法题解-计算位置x到y的最少步数 | 豆包MarsCode AI刷题

172 阅读4分钟

问题描述

AB 实验同学每天都很苦恼如何可以更好地进行 AB 实验,每一步的流程很重要,我们目标为了缩短所需的步数。 我们假设每一步对应到每一个位置。从一个整数位置 x 走到另外一个整数位置 y,每一步的长度是正整数,每步的值等于上一步的值 -1+0+1。求 xy 最少走几步。并且第一步必须是 1,最后一步必须是 1,从 xy 最少需要多少步。 ## 样例说明 - 整数位置 x12,另外一个整数位置 y6,我们需要从 x 走到 y,最小的步数为:1221,所以我们需要走 4 步。

解题思路

刚开始我的想法是暴力模拟,设置变量表示步长、步数、剩余步数......,模拟半天最终放弃,这时候才看到样例也是巨大,无法模拟,那就只能琢磨聪明一点的方法了

题目中说第一步长度为1,且最后一步长度也为1,并且每次步长只能加一减一或是不变,按照贪心的想,想要所走步数最少,那么我的步长就要尽可能的大,所以最终的答案大体上是一个慢慢上升,又慢慢下降的序列,中间可能会夹杂着一些相等的数

d195e5807949486aa35b8e2d56536578.png 假设最大步长为k,那么所走步数一定是先从1加到K,然后又从K减为1 ,类似上图         在答案中可能会有两步步长一样长的情况,所以这个序列真实情况不一定是对称的,为了方便计算我们现在只表示答案序列中的连续部分,假设答案中的所有数字和为diff(即起点终点之间的距离)         

前面上升序列 (1+2+......+k)=k*(k+1)/2    后面的下降序列(k-1+.......+1)=k*(k-1)/2 都是公差为1的等差数列,那么答案序列中未被计算的长度 remain=diff - k*(k+1)/2 - k*(k-1)/2         

目前已知步数就是 k(前半部分被记入的步数) 和 k-1(后半部分被记入的步数),接下来贪心的把剩余步数remain走完,我们已经有了一个连续的步数序列,并且相邻的步数的长度可以相同,那么剩余部分中大于最大步长k的部分我们就用k去走,循环减去k去走就可以了,然后剩余的小于k的距离我们一步就可以走完(将它插入到我们已经计算的连续等差数列中去)        

例如题目中所给样例答案,123221,利用上面的思路,其中最大的步长为3,我们摘出来上升数列和下降数列后,剩余距离为2,小于最大步长,所以可以直接塞入答案序列当中,一步就能完成        

那么这个最大步长k是多少呢?最简单的方式直接从1开始枚举,最大不可能超过两点的距离。如果想要代码节省一点时间,我们可以想一下最大的步长会是多少呢?通过上面我们知道答案序列可以表示为  k*(k+1)/2 + k*(k-1)/2 +剩余距离,当剩余距离为0,左边的k才可能达到最大值

即   k*(k+1)/2 + k*(k-1)/2=diff,化简可以得到k*k=diff,即步长最大为根号diff,所以我们从1枚举到根号diff即可。         

这题不能扣细节,要把有序的部分拿出来,处理好有序的数据后在处理杂乱无章的那些步数。下面上代码

代码

public class Main {
public static int solution(int xPosition, int yPosition) {
// Please write your code here
int start=Math.min(xPosition,yPosition);
int end=Math.max(yPosition,xPosition);
int diff=end-start;
int ans=Integer.MAX\_VALUE;

//枚举步数的最大值
for(int i=1;i*i<=diff;i++){

    int sum=f(i)+f(i-1);//计算既定的走过的长度
    int remain=diff-sum,cnt=0;//剩余多少

    //按此种最大步长行走不妥则退出
    if(remain<0){
        break;
    }
    //如果剩余步数大于最大步长,则以最大步长行走
    while(remain>i){
        remain-=i;
        cnt++;
    }

    //剩余步数大于0小于最大步长,可以一步走出
    if(remain>0){
        cnt++;
    }
    
    ans=Math.min(ans, cnt+2*i-1);
}

return ans;
}
public static int f(int x){
int k=x*(x+1)/2;

return k;
}

public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution(12, 6)==4 );
System.out.println(solution(34, 45) ==6);
System.out.println(solution(50, 30) ==8);
}