移掉 K 位数字
难度:
标签:
题目描述
给你一个以字符串表示的非负整数 num
和一个整数 k
,移除这个数中的 k
位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。
示例 1 :
输入:num = "1432219", k = 3 输出:"1219" 解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。
示例 2 :
输入:num = "10200", k = 1 输出:"200" 解释:移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :
输入:num = "10", k = 2 输出:"0" 解释:从原数字移除所有的数字,剩余为空就是 0 。
提示:
1 <= k <= num.length <= 105
num
仅由若干位数字(0 - 9)组成- 除了 0 本身之外,
num
不含任何前导零
代码结果
运行时间: 30 ms, 内存: 17.3 MB
/*
* 思路:
* 使用Java Stream API,我们可以将字符串转换为字符流,
* 然后使用一个栈来存储字符。在字符流处理过程中,
* 对每个字符进行与栈顶元素的比较,并决定是否弹出栈顶元素。
* 最终将栈中的字符组合成结果字符串并处理前导零。
*/
import java.util.Stack;
import java.util.stream.Collectors;
public class Solution {
public String removeKdigits(String num, int k) {
Stack<Character> stack = new Stack<>();
num.chars().mapToObj(c -> (char) c).forEach(digit -> {
while (!stack.isEmpty() && stack.peek() > digit && k > 0) {
stack.pop();
k--;
}
stack.push(digit);
});
while (k > 0) {
stack.pop();
k--;
}
String result = stack.stream()
.map(String::valueOf)
.collect(Collectors.joining());
result = result.replaceAll("^0+(?!$)", "");
return result.isEmpty() ? "0" : result;
}
}
解释
方法:
这个题解使用了贪心算法和单调栈的思路。我们从左到右遍历数字,对于每个数字,如果当前数字小于栈顶元素,则弹出栈顶元素,直到栈为空或者栈顶元素小于等于当前数字。这样可以保证栈中的元素是单调递增的。最后,我们取出栈中前 remain 个元素作为结果,其中 remain 为原数字长度减去要删除的数字个数 k。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在遍历数字时,选择在当前数字小于栈顶元素时执行出栈操作?这样的操作有什么特殊意义?
▷🦆
在贪心算法的选择过程中,如果后面的数字和栈顶元素相等,为什么没有特别的处理措施?这种情况下保留哪一个数字更优?
▷🦆
代码中`lstrip('0') or '0'`这部分的处理是为了解决什么问题?在什么情况下会出现需要这样处理的场景?
▷🦆
如果输入的数字已经是最小可能值,例如 num = '12345', k = 3,这时算法的行为是什么?是否还会进行出栈操作?
▷相关问题
拼接最大数
给你两个整数数组 nums1
和 nums2
,它们的长度分别为 m
和 n
。数组 nums1
和 nums2
分别代表两个数各位上的数字。同时你也会得到一个整数 k
。
请你利用这两个数组中的数字中创建一个长度为 k <= m + n
的最大数,在这个必须保留来自同一数组的数字的相对顺序。
返回代表答案的长度为 k
的数组。
示例 1:
输入:nums1 = [3,4,6,5], nums2 = [9,1,2,5,8,3], k = 5 输出:[9,8,6,5,3]
示例 2:
输入:nums1 = [6,7], nums2 = [6,0,4], k = 5 输出:[6,7,6,0,4]
示例 3:
输入:nums1 = [3,9], nums2 = [8,9], k = 3 输出:[9,8,9]
提示:
m == nums1.length
n == nums2.length
1 <= m, n <= 500
0 <= nums1[i], nums2[i] <= 9
1 <= k <= m + n