题目
给定一个用字符串表示的非负整数num,从这个整数中去掉k个数字,使得到的数字最小。
思路
- 暴扫,组合出剩余位数的全都可能的数字,逐个插入堆中,最后取出堆顶元素,TLE
- 思考发现从左到右逐个扫描数字,如果后一个数字小于等于前一个数字,就把前一个数字去掉,得到的就是去掉一个数字以后的最小数字,依此类推,直到扫到最后一个数字,这时整个数字是按位数字从小到大排列的,如果此时去掉的数字不足k个,就从最后一位逐个向左去除,也就是此时的数字保留len(num)-k位,这种方法既可以用堆栈也可以用指针实现。用指针的话pop列表比较慢,将pop操作改成重新拼接两个字符串更快一点,但是空间耗费比较大,用堆栈的话时空复杂度都更低。
代码
# brute
import heapq
from itertools import combinations
len_num = len(num)
if len_num == k:
return 0
a = combinations(num, len_num - k)
h = []
while True:
try:
heapq.heappush(h, int(''.join(next(a))))
except StopIteration:
break
return str(h[0])
# stack
len_num = len(num)
if len_num < 2 or len_num == k:
return '0'
stack = []
counter = 0
for i in num:
if not stack:
stack.append(i)
continue
while stack and i < stack[-1] and counter < k:
stack.pop()
counter += 1
if counter == k:
break
stack.append(i)
return str(int(''.join(stack)))[:len_num-k]
# pointer
len_num = len(num)
if len_num < 2 or len_num == k:
return '0'
i = 0
counter = 0
while counter < k:
if int(num[i]) <= int(num[i + 1]):
if i == len(num) - 2:
break
else:
i = i + 1
else:
num = num[:i] + num[i + 1:]
if i > 0:
i = i - 1
counter += 1
return str(int(num))[:len_num - k]