题目:
给你一个下标从 0 开始的字符串 num
,表示一个非负整数。在一次操作中,您可以选择 num
的任意一位数字并将其删除。请注意,如果你删除 num
中的所有数字,则 num
变为 0
。
返回最少需要多少次操作可以使 num
变成特殊数字。如果整数 x
能被 25
整除,则该整数 x
被认为是特殊数字。
示例 1:
输入:num = "2245047"
输出:2
解释:删除数字 num[5] 和 num[6] ,得到数字 "22450" ,可以被 25 整除。
可以证明要使数字变成特殊数字,最少需要删除 2 位数字。
示例 2:
输入:num = "2908305"
输出:3
解释:删除 num[3]、num[4] 和 num[6] ,得到数字 "2900" ,可以被 25 整除。
可以证明要使数字变成特殊数字,最少需要删除 3 位数字。
示例 3:
输入:num = "10"
输出:1
解释:删除 num[0] ,得到数字 "0" ,可以被 25 整除。
可以证明要使数字变成特殊数字,最少需要删除 1 位数字。
提示
1 <= num.length <= 100
num
仅由数字'0'
到'9'
组成num
不含任何前导零
技巧枚举
思路:
// 思路1:暴力枚举所有 num 的删除情况 (删1个,2个 ... 判断是不是25的倍数) 时间复杂度:非常大
//思路2:从25的倍数 target 出发,寻找num要达到 target 最少的删除次数 (停止条件为25 的倍数 target > num),那其实就是判断target是不是num的子序列。这样时间复杂度就下降了
代码:
class Solution {
public:
int isChild(string num, string target) {
int i = 0, j = 0;
while (i < num.size()) {
if (num[i] == target[j]) {
j++;
}
i++;
}
return j == target.size() ? num.size() - target.size() : -1;
}
int minimumOperations(string num) {
int n = num.size(), res;
long long cur = 25;
int zero_idx = num.find('0');
if (zero_idx == string::npos) {
res = n;
}else {
res = n - 1;
}
while (true) {
string target = to_string(cur);
if (target.size() > num.size()) {
break;
}
int ret = isChild(num, target);
if (ret != -1) {
res = min(res, ret);
}
cur += 25;
}
return res;
}
};
贪心算法
思路:
一个数字要想被 25 整除,它需要满足以下条件:
如果它的位数为 1,则它必须是 0。
如果它的位数为 2,则它必须是 25,50 或者 75。
如果它的位数为大于等于 3,则它必须以 00,25,50 或者 75结尾。
我们需要将字符串 num 进行最少步数的操作,使其满足以上条件之一。题目又规定了 num 不包含前导 0,因此不可能存在经过最少步数的操作,使得 num 变为 00,所以这一特殊情况不在以上条件的讨论范围里。
我们从右至左遍历 num,
如果遇到 0 或 5:
如果在这之前遇到过 0,则将这之前的 0,当前的数字,以及当前的数字以左的数字都保留,其他的数字删除。记 num 长度为 n,当前下标为 i,最少操作数即为 n − i − 2。
如果在这之前没有遇到过 0,则标记一下状态,表示遇到了 0 或 5。
如果遇到 2 或 7:
如果在这之前遇到过 5,则将这之前的 5,当前的数字,以及当前的数字以左的数字都保留,其他的数字删除。记 num 长度为 n,当前下标为 i,最少操作数即为 n − i − 2。
如果遍历完都没有找到最少操作数,那么说明我们不可能通过操作来使得 num 变得以 00,25,50 或者 75 结尾。
如果我们在遍历中遇到了 0,那么我们就删除其他所有数字,只保留这个 0,返回 n − 1。
否则,我们将所有数字删除,返回 n。
代码:
class Solution {
public:
int minimumOperations(string num) {
int n = num.size();
bool find0 = false, find5 = false;
for (int i = n - 1; i >= 0; i--) {
if (num[i] == '0' || num[i] == '5') {
if (find0) {
return n - i - 2;
}
if (num[i] == '0') {
find0 = true;
}else {
find5 = true;
}
}
else if (num[i] == '2' || num[i] == '7') {
if (find5) {
return n - i - 2;
}
}
}
if (find0) {
return n - 1;
}
return n;
}
};