https://leetcode.com/problems/least-operators-to-express-number/
给定一个正整数 x > 2 x>2 x>2,和另一个正整数 t ≥ 1 t\ge 1 t≥1。允许使用加减乘除和数字 x x x构造一个表达式,问至少需要多少个运算符可以使得表达式恰好等于 t t t。
首先, x / x , x , x × x , x × x × x , . . . x/x, x, x\times x, x\times x\times x,... x/x,x,x×x,x×x×x,...分别能得到 x 0 , x , x 2 , x 3 , . . . x^0,x,x^2,x^3,... x0,x,x2,x3,...,接着将 t t t按 x x x进制分解为 t = + a 0 + a 1 x + a 2 x 2 + . . . t=+a_0+a_1x+a_2x^2+... t=+a0+a1x+a2x2+...(我们先假设每个乘积项前面都有个正号 + + +),这样我们只需要一步一步把 a i a_i ai凑出来即可。可以递归地来做。我们考虑当前正在用 x k x^k xk在修改 s = a k x k s=a_kx^k s=akxk,那么显然 x k x^k xk要去修改 a k a_k ak使之成为 0 0 0(这是因为如果用 x k − 1 x^{k-1} xk−1去修改 a k a_k ak不会得到更小的代价)。如果 s = 0 s=0 s=0,那么修改代价就是 0 0 0;如果 s = 1 s=1 s=1,那么修改代价是,当 k = 0 k=0 k=0的时候是 c k = 2 c_k=2 ck=2,因为是 + x / x +x/x +x/x;否则代价是 c k = k c_k=k ck=k,即 + x × x × . . . +x\times x\times ... +x×x×...;对于别的情况,凑 a k a_k ak的代价可以是通过先凑 a k c k a_kc_k akck,然后继续凑剩余数字,也可以通过先凑 ( x − a k ) c k (x-a_k)c_k (x−ak)ck,然后凑剩余数字加上 x k + 1 x^{k+1} xk+1,取两者较小的即可。上述凑最小代价可能同个情况被算多次,所以需要记忆化搜索。代码如下:
class Solution {
public:
int leastOpsExpressTarget(int x, int target) {
unordered_map<string, int> mp;
return dfs(target, 0, x, mp) - 1;
}
int dfs(int target, int i, int x, unordered_map<string, int>& mp) {
string s = to_string(target) + "#" + to_string(i);
if (mp.count(s)) return mp[s];
int cost = i ? i : 2;
if (!target) return mp[s] = 0;
if (target == 1) return mp[s] = cost;
int d = target / x, r = target % x;
if (!r) return mp[s] = dfs(d, i + 1, x, mp);
return mp[s] = min(dfs(d, i + 1, x, mp) + r * cost,
dfs(d + 1, i + 1, x, mp) + (x - r) * cost);
}
};
时空复杂度 O ( log t ) O(\log t) O(logt)。