持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
题目
给你一个以字符串表示的非负整数 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 <= 10^5num仅由若干位数字(0 - 9)组成- 除了 0 本身之外,
num不含任何前导零
思考
本题难度中等。
首先是读懂题意。根据题目描述我们可知,字符串 num经过删除k个字符后,返回得到的数字。考虑字符串"1432219",我们的策略是删除尽可能大的数字,比如"143"中,我们会优先删除数字4,保留数字3。依次类推,会优先删除"1432"中的"43",保留数字"12"。
对于字符串num,我们的策略是:
-
从左至右进行遍历,当前的数字先入栈暂存。
-
对于「依次递增」的数如12345,我们会尽量删除低位。
-
对于「依次递减」的数如54321,我们会尽量删除高位。
所以,如果当前遍历的数字比栈顶大,符合递增,我们会让它入栈。如果当前遍历的数比栈顶小,栈顶立刻出栈,直至k为0。
最后,直至k为0时,栈中保存的数字即为答案。
解答
方法一:单调栈
/**
* @param {string} num
* @param {number} k
* @return {string}
*/
var removeKdigits = function(num, k) {
let stack = []
// 遍历字符串num
for(digit of num) {
while(k > 0 && stack.length && stack[stack.length - 1] > digit) {
stack.pop()
k--
}
// 当前字符不是"0"或当前字符是"0"且栈非空(避免前导零)
if (digit != '0' || stack.length != 0) {
stack.push(digit)
}
}
// 从stack继续删,直到k=0
while (k > 0) {
stack.pop()
k--
}
return stack.length === 0 ? "0" : stack.join('')
}
// console.log(removeKdigits('1432219', 3)) // '1219'
// console.log(removeKdigits('10200', 1)) // '200'
// console.log(removeKdigits('9', 1)) // '0'
// 执行用时:88 ms, 在所有 JavaScript 提交中击败了22.75%的用户
// 内存消耗:46.3 MB, 在所有 JavaScript 提交中击败了75.85%的用户
// 通过测试用例:43 / 43
复杂度分析:
- 时间复杂度:O(n),其中 n 为字符串的长度。
- 空间复杂度:O(n)。栈存储数字需要线性的空间。