leetcode
leetcode 2501 ~ 2550
使 X 和 Y 相等的最少操作次数

使 X 和 Y 相等的最少操作次数

难度:

标签:

题目描述

You are given two positive integers x and y.

In one operation, you can do one of the four following operations:

  1. Divide x by 11 if x is a multiple of 11.
  2. Divide x by 5 if x is a multiple of 5.
  3. Decrement x by 1.
  4. Increment x by 1.

Return the minimum number of operations required to make x and y equal.

 

Example 1:

Input: x = 26, y = 1
Output: 3
Explanation: We can make 26 equal to 1 by applying the following operations: 
1. Decrement x by 1
2. Divide x by 5
3. Divide x by 5
It can be shown that 3 is the minimum number of operations required to make 26 equal to 1.

Example 2:

Input: x = 54, y = 2
Output: 4
Explanation: We can make 54 equal to 2 by applying the following operations: 
1. Increment x by 1
2. Divide x by 11 
3. Divide x by 5
4. Increment x by 1
It can be shown that 4 is the minimum number of operations required to make 54 equal to 2.

Example 3:

Input: x = 25, y = 30
Output: 5
Explanation: We can make 25 equal to 30 by applying the following operations: 
1. Increment x by 1
2. Increment x by 1
3. Increment x by 1
4. Increment x by 1
5. Increment x by 1
It can be shown that 5 is the minimum number of operations required to make 25 equal to 30.

 

Constraints:

  • 1 <= x, y <= 104

代码结果

运行时间: 27 ms, 内存: 16.4 MB


// Java Stream solution
// 思路:与Java解法相同,Java Stream不适合处理复杂的控制流,使用Java解法实现即可。
import java.util.LinkedList;
import java.util.Queue;

public class MinOperationsStream {
    public int minOperations(int x, int y) {
        if (x == y) return 0;
        Queue<int[]> queue = new LinkedList<>();
        queue.offer(new int[]{x, 0});
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int val = current[0];
            int steps = current[1];
            if (val == y) return steps;
            if (val % 11 == 0) queue.offer(new int[]{val / 11, steps + 1});
            if (val % 5 == 0) queue.offer(new int[]{val / 5, steps + 1});
            queue.offer(new int[]{val - 1, steps + 1});
            queue.offer(new int[]{val + 1, steps + 1});
        }
        return -1;
    }
}

解释

方法:

这个题解采用了递归的方法,结合记忆化搜索(通过 @cache 装饰器实现),来找到将 x 变为 y 的最少操作次数。如果 x 小于等于 y,直接返回 y - x,因为这种情况下只能通过增加操作使 x 等于 y。当 x 大于 y 时,有五种可能的操作:直接减去 x - y,或者通过除以 11 或 5,并考虑到整除后的余数,决定是直接除还是除后再加 1 来尽可能接近 y。递归调用处理除以 11 和 5 的情况,并考虑余数带来的额外操作,最终取所有情况的最小值。

时间复杂度:

O(log(x) * log(y))

空间复杂度:

O(log(x) * log(y))

代码细节讲解

🦆
对于操作选项中的`如果x是11的倍数,将x除以11`,如果x正好是11的倍数,为何在题解中还考虑了11 - x % 11 + 1这种情况?
在这个算法中,考虑了11 - x % 11 + 1这种情况,是为了处理x不是11的倍数时的情形。当x不是11的整数倍时,x % 11得到的余数不为0,此时x除以11后还需要进一步的操作使其更接近y。选项11 - x % 11 + 1表示我们将x除以11后,还需要额外加1以确保能整除11,然后再处理余数,这样可以确保在余数大于11的一半时通过加1操作达到更少的总操作次数。即使x是11的倍数,也需要这种考虑来处理通用情况,确保算法的完整性和正确性。
🦆
递归解法中,为什么选择使用min函数对所有操作可能性进行比较?在什么情况下,直接减少x到y是最优解?
递归解法中使用min函数是为了在所有可能的操作中选择最小的操作次数,从而确保找到将x变为y所需的最少操作次数。直接减少x到y是最优解的情况通常出现在x与y相差不大,且其它操作(如除以11或5后再进行调整)所需的步骤会更多时。特别是当x稍大于y,直接减掉差值通常比进行多次除法和余数处理要高效。
🦆
在题解中提到,如果x小于等于y,直接返回y - x。这种做法是否考虑了所有情况,例如如果x刚好是y的11倍或5倍的情况,是否有更优解法?
题解中这种做法简单直接,适用于x小于等于y的情况下,确保操作次数是最少的,因为直接增加差值是最直接的方法。如果x刚好是y的11倍或5倍,虽然理论上存在通过多次除法可能减少到y的情况,但从实用角度出发,如果x小于等于y,进行增加操作无疑是最简单直接的方法。在实际问题中,通常考虑操作的复杂性和实现的直观性,直接增加差值是最符合逻辑的选择。
🦆
在处理x除以11或5后的余数,题解中选择了加1或直接处理余数的方式,这种策略如何保证操作次数最少?
这种策略通过考虑所有可能的余数处理方式来寻找最小的操作次数。加1或直接处理余数的决策基于尝试使x尽可能快地逼近y的原则。如果余数较小,直接处理余数通常是更优的;如果余数较大,通过增加1后再处理余数可能会更接近y,从而减少总的操作次数。通过递归和min函数的组合,算法能够在所有这些可能的情况中找到最优解,并确保每一步都是向着最小操作次数前进。

相关问题