MarosCode题目——计算位置 x 到 y 的最少步数

39 阅读4分钟

最小步数求解思路

问题描述

从位置 x 到位置 y 的最小步数问题,每一步的长度是正整数,每步的值为上一步的值 -1、0 或 +1,第一步和最后一步必须是 1。

样例分析

  • 输入 (12, 6),最小步数为 4。
  • 输入 (34, 45),最小步数为 6。
  • 输入 (50, 30),最小步数为 8。

解法一:归纳总结+二叉搜索

  1. 这里看这个示例突然想到了,1.2.3.4……n这个排列的和,然后就发现 (n*(n-1)/2)*2 = 差值,最后return n✖️2

  2. 有了这个思路之后再看看示例,6,11,20,而 n*(n-1)/2 公式中 n 大致为2,3,4,所以步数是4,6,8

    但是假如 差值14呢? 最小步数是 1232 ,321

    是7步,但是最中间的‘2’的值可以是,2,3,4,所以7步实现的差值范围是,[14,16]

  3. 这里其实有点启发,那思路其实完全可以是,走n最大实现的差值是多少?然后去二叉搜索这个n呀

  // 这里归纳一下:
    // 1步 : 最多走1个距离 
    // 2步 : 最多走 2个距离 -> (2*4)/4
    // 3步 : 最多走4个距离 ->((3-1)*(3-1+2))/2+(3+1)/2
    // 4步 : 最多走6个距离 ->(4*6)/4
    // 5步 :最多走 9个距离
    // 6步 :最走12个距离 ->(6*8)/4
    // 7步 :最多走 16个距离
    // 8步 : 最多走 20个距离 -> (8*10)/4

所以:通过归纳法总结出公式了,

当n = 偶数 ,最大可以走 *(n(n+2))/4**个距离,当

n = 奇数,n=n-1,最大可以走 ((n-1)*(n+1))/4 + (n+1)/2步

既然公式有了,就可以直接用二叉搜索,进行逼近

解法二:公式推导

  1. 步长变化规律:

    • 由于每一步的步长只能变化 -10+1,并且步长必须为正整数,这意味着步长序列是一个先增加后减少的序列,或者保持不变,然后减少,形成一个“山峰”形状。
    • 第一步和最后一步的步长为 1,进一步强化了步长序列的对称性。
  2. 考虑步长序列的可能形式:

    • 为了使总步数最少,步长序列应该尽可能地先增加步长,然后再减少步长。

    • 例如,对于步长最大值为 m 的序列,步长可以是:

      • 当步数为奇数时:[1, 2, 3, ..., m, ..., 3, 2, 1],步数为 2m - 1
      • 当步数为偶数时:[1, 2, 3, ..., m, m, ..., 3, 2, 1],步数为 2m
  3. 建立步数与距离的关系: (这里的公式推导其实是等差数列)

    • 当步数为奇数(N = 2m - 1)时:

      • 总距离 S = 1 + 2 + 3 + ... + m + ... + 3 + 2 + 1 = m^2
    • 当步数为偶数(N = 2m)时:

      • 总距离 S = 1 + 2 + 3 + ... + m + m + ... + 3 + 2 + 1 = m(m + 1)
  4. 推导最小步数的计算方法:

    • 给定距离 D = |y - x|,需要找到最小的 m,使得总距离 S 不小于 D

    • 算法步骤:

      • 初始化 m = 1

      • 判断:

        • 如果 D <= m^2,则最小步数为 N = 2m - 1
        • 如果 m^2 < D <= m(m + 1),则最小步数为 N = 2m
        • 否则,m += 1,重复上述判断。
        • (这里奇数和偶数的m时候,是总步长的最大值)
 public static int solution(int xPosition, int yPosition) {
        int D = Math.abs(xPosition - yPosition);
        if (D == 0) return 0;

        int m = 0;
        while (true) {
            m++;
            if (D <= m * m) {
                return 2 * m - 1;
            } else if (D <= m * (m + 1)) {
                return 2 * m;
            }
        }
    }

解法三:动态规划(失败了)

这个题不适合用dp,记录一下思考过程,有同学发现问题的话麻烦给一些建议

动态规划
这里求最小,然后又给出了“每步的值等于上一步的值 `-1``+0``+1`”
这样的选择,很自然联想到了动态规划
动态规划四个要素 1.状态 2.选择 3.定义dp 4.转移方程

1. 状态有哪些?步长 ,第i步的值,第i步最大能到达的值
选择是什么?每步的值等于上一步的值 `-1``+0``+1`
基于这些条件我们可以怎么定义p数组?
dp[i][j] 表示 第i步的最大的步长和是j
但是这样用不到选择呀
dp[i][j] 表示 第i步的步长是j,然后总和是最大
dp[i][j] = dp[i-1][j]或dp[i-1][j]或dp[i-1][j]
但是这样的条件有什么用呢?
什么时候选什么条件呢?

if (remain>n/2) ,这个时候就放心加 dp[i][j] = dp[i-1][j]+1
if(remain==n/2) dp[i][j] = dp[i-1][j]
if(remain<n/2) dp[i][j] = dp[i-1][j]-1
if(remain==0) return i+1;

但是这里问题变得复杂了又要解决奇偶问题了
所以这里dp[i][j]表示到达第i步到达最小位置j所需要的最小步数