leetcode
leetcode 851 ~ 900
表示数字的最少运算符

表示数字的最少运算符

难度:

标签:

题目描述

代码结果

运行时间: 32 ms, 内存: 0.0 MB


/*
 * Problem: Given a positive integer x, we need to write an expression using x and operators (+, -, *, /) such that the expression equals a given target value. The goal is to use the minimum number of operators.
 *
 * Approach:
 * 1. This is a complex problem and not particularly well-suited to Java Streams because it requires a recursive search with memoization.
 * 2. For demonstration purposes, we show a simplified use of streams in a recursive helper function.
 */

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

public class MinOperatorsStream {
    private Map<Long, Integer> memo = new HashMap<>();

    public int minOperators(int x, int target) {
        return helper((long) x, (long) target);
    }

    private int helper(long x, long target) {
        if (x == target) return 0;
        if (memo.containsKey(target)) return memo.get(target);

        long quotient = target / x;
        long remainder = target % x;

        int result = Stream.of(
                remainder == 0 ? helper(x, quotient) + 1 : Integer.MAX_VALUE,
                helper(x, quotient) + (int) remainder + 1,
                helper(x, quotient + 1) + (int) (x - remainder) + 1
        ).min(Integer::compare).orElse(Integer.MAX_VALUE);

        memo.put(target, result);
        return result;
    }

    public static void main(String[] args) {
        MinOperatorsStream mos = new MinOperatorsStream();
        System.out.println(mos.minOperators(3, 19)); // Output: 5
        System.out.println(mos.minOperators(5, 501)); // Output: 8
        System.out.println(mos.minOperators(100, 100000000)); // Output: 3
    }
}

解释

方法:

该题解采用动态规划方法,通过计算当前数值能被表示的最小操作数,逐步递推至目标值。利用正数(pos)和负数(neg)两个变量,分别记录达到当前数值的最小正表达式和最小负表达式所需的运算符数量。通过不断地对目标值 target 进行 x 的除法,计算每步的余数以决定使用加法或乘法的数量,同时也考虑通过余数来决定是否可以通过少量的减法或除法来达到目标。最后,根据最终得到的 pos 和 neg 的值,计算出包括转换方向的运算符总数,并减去一个基础值,得到最小运算符的总数。

时间复杂度:

O(log_x(target))

空间复杂度:

O(1)

代码细节讲解

🦆
如何保证在每次迭代中使用除法和取余得到的当前最小表示是最优的?
在动态规划中,通过每次迭代更新的方式来确保每一步的最小表示都是最优的。在每次迭代中,我们都会根据当前的余数来选择是增加还是减少操作数。通过逐步构建从基数x到target的最小操作路径,并在每次迭代中考察所有可能的操作(加法、减法、乘法),保证了每一步的决策都是在当前条件下最优的。这种方法利用了动态规划的特性,即通过局部最优解的累积来达到全局最优解。
🦆
在更新pos和neg的过程中,min函数中的各个选项具体代表什么意义?具体是如何通过这些计算达到最少运算符的?
在更新pos和neg的过程中,min函数用于选择达到当前数字的最少运算符数量。对于pos,其选项`cur * k + pos`代表如果直接使用加法达到当前数字所需的操作数,而`(cur + 1) * k + neg`代表通过稍微超过当前数字后再减少一些的操作数。对于neg,`(x - cur) * k + pos`表示尝试达到稍大于当前数字然后减少的方式,而`(x - cur - 1) * k + neg`代表从更大的数减少更多以达到当前数字的操作数。这些计算考虑了所有可能的方式来最小化运算符的使用,确保每一步都是最优的。
🦆
为什么在k为0的初始情况下,将pos和neg设置为cur*2和(x-cur)*2,这里的乘以2是基于什么考虑?
在k为0的初始情况下,pos和neg设置为cur*2和(x-cur)*2是因为这是构建初始状态时的基本操作数。这里的乘以2代表了构建当前数字的基础运算符数(1次乘法和1次加法或减法)。例如,使用x的1次方(即x本身)来表达cur需要cur次加法,因为要加cur次x,而每次加法都需要一个操作符。同样地,使用x的1次方表达x-cur需要(x-cur)次减法。所以,乘以2反映了这两种基础操作的运算符数量。
🦆
在最后返回结果时,为什么要从min(pos, k + neg)的结果中减去1?
在最后返回结果时,从min(pos, k + neg)的结果中减去1是为了调整最后的运算符总数,确保不计算多余的加法或乘法转换。由于在算法的开始阶段,我们初始化了pos和neg的值来反映基础操作,这些操作已经包括了从0开始构建表达式所需的运算符。因此,在最终计算完成后,需要减去这个最初的基础操作(通常是一个额外的乘法),以得到精确的最小运算符总数。

相关问题