Leetcode每日一题2020.11.15第402题:移掉K位数字

402.移掉K位数字

题目描述

在这里插入图片描述
在这里插入图片描述

思路、算法及代码实现

贪心+单调栈:
对于两个相同长度的数字序列,最左边不同的数字决定了这两个数字的大小,例如,对于A=1axxx,B=1bxxx,如果a>b则A>B。
基于此,我们可以知道,若要使得剩下的数字最小,需要保证靠前的数字尽可能小。
基于上述分析,我们可以得出“删除一个数字”的贪心策略:
给定一个长度为n的数字序列[D0D1D2D3…Dn-1],从左往右找到第一个位置i(i>0)使得Di<Di-1,并删去Di-1;如果不存在,说明整个数字序列单调不降,删去最后一个数字即可。
基于此,我们可以每次对整个数字序列执行一次这个策略;删去一个字符后,剩下的n-1长度的数字序列就形成了新的子问题,可以继续使用同样的策略,直至删除k次。
然而暴力的实现复杂度最差会达到O(nk)(考虑整个数字序列是单调不降的),因此我们需要加速这个过程。
考虑从左往右增量的构造最后的答案。我们可以用一个栈维护当前的答案序列,栈中的元素代表截止到当前位置,删除不超过k次个数字后,所能得到的最小整数。根据之前的讨论:在使用k个删除次数之前,栈中的序列从栈底到栈顶单调不降。
因此,对于每个数字,如果该数字小于栈顶元素,我们就不断地弹出栈顶元素,直到

  • 栈为空
  • 或者新的栈顶元素不大于当前数字
  • 或者我们已经删除了k位数字
    上述步骤结束后我们还需要针对一些情况做额外地处理:
  • 如果我们删除了m个数字且m<k,这种情况下我们需要从序列尾部删除额外地k-m个数字。
  • 如果最终的数字序列存在前导零,我们要删去前导零。
  • 如果最终数字序列为空,我们应该返回0。
    最终,从栈底到栈顶的答案序列即为最小数。
    考虑到栈的特点是后进先出,如果通过栈实现,则需要将栈内元素依次弹出然后进行翻转才能得到最小数。为了避免翻转操作,可以使用双端队列代替栈的实现。
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_51210480/article/details/109755372
今日推荐