洛谷:P1106:删数问题


洛谷:P1106:删数问题

题目

洛谷:P1106:删数问题

分析

这道题目的有趣之处在于:题意很容易理解,一般也能想到“贪心”,但是怎么贪心呢?

我们先看几道例题,我们先看一个5位数,拿掉一个数字:

12345 => 1234。观察到:所有数字顺序排列,那么最后一个数字(也就是最大的数字)可以被删除。

12354 => 1234。观察到:数字5出现在4之前(逆序对),那么就要删除5而不是4

越大的数字位数越高(这里是越早出现),构成了逆序对,这样的数字应该尽早拿掉。换句话说,我们要构造一个高位(早出现)尽可能小、低位(晚出现)尽可能大的数字。

核心做法:

  1. 从左到右扫描
  2. 如果i位和i+1位的数字构成逆序对:去掉i,保留i+1。否则保留ii+1
  3. 如此操作后如果还需要拿走数字,那么从最后开始去掉。

这是因为,当我们扫描完所有数字并消除了所有逆序对后,如果还有剩余的删除次数,那么剩下的数字呈现非递减(不会递减)的特性。这意味着从左到右,数字要么增加,要么保持不变。

我们保留的数字中,一定是在最高位保留了较小的数字——符合题目的要求。

用栈来实现

这种比较、踢出、保留的描述和栈是一致的。所以,我们应该用栈来实现。

    // 从左到右扫描数字
    for (char digit : n)
    {
        // 如果当前数字比栈顶元素小,且还有删除次数,则删除栈顶元素
        while (!stack.empty() && stack.back() > digit && k > 0)
        {
            stack.pop_back();
            k--;
        }
        stack.push_back(digit);
    }

    // 如果还有删除次数,从栈的末尾删除
    while (k > 0 && !stack.empty())
    {
        stack.pop_back();
        k--;
    }

答案

Solution

思考

请认真阅读代码(22-31行),这是本题解法的关键。

上一篇 下一篇