给定数量N消除K个数字以获得最大可能数量

时间:2014-02-07 15:35:00

标签: c++ algorithm

正如标题所说,任务是:

给定数字N消除K位数以获得最大可能数量。数字必须保持在他们的位置。

示例:n = 12345k = 3max = 45(前三位数字被删除,数字不得移动到其他位置)。

知道如何解决这个问题吗? (这不是家庭作业,我正准备进行算法竞赛并解决在线评委的问题。)

1 <= N <= 2^601 <= K <= 20

编辑:这是我的解决方案。它的工作原理:))

#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <cmath>

using namespace std;


int main()
{
    string n;
    int k;

    cin >> n >> k;

    int b = n.size() - k - 1;
    int c = n.size() - b;
    int ind = 0;
    vector<char> res;
    char max = n.at(0);

    for (int i=0; i<n.size() && res.size() < n.size()-k; i++) {
        max = n.at(i);
        ind = i;
        for (int j=i; j<i+c; j++) {
            if (n.at(j) > max) {
                max = n.at(j);
                ind = j;
            }
        }

        b--;
        c = n.size() - 1 - ind - b;
        res.push_back(max);
        i = ind;
    }

for (int i=0; i<res.size(); i++)
    cout << res.at(i);

cout << endl;

    return 0;
}

3 个答案:

答案 0 :(得分:3)

蛮力应该足够快以适应您的限制:n将有最多19位数字。使用numDigits(n)位生成所有正整数。如果设置了k位,则删除与设置位对应的位置的数字。将结果与全局最优值进行比较,并根据需要进行更新。

复杂性:O(2^log n * log n)。虽然这似乎与O(n)渐近相似,但在实践中它会更快,因为O(2^log n * log n)中的对数是10的对数,这将给出更小的值(log base 10的1 + n为您提供n的位数。

您可以通过一次生成log n n n - k组合的组合来避免n - k因素,并在生成每个given n, pick n - k digits in order such that the resulting number is maximum时生成由所选d个位置组成的数字组合(将其作为参数传递)。这基本上意味着您解决了类似的问题:{{1}})。

注意:有一种方法可以解决这个问题,但这并不涉及蛮力,但我也想向OP展示这个解决方案,因为他在评论中询问了如何强制执行。对于最佳方法,请研究如果我们从左到右逐位构建数字会发生什么,并且对于每个数字{{1}},我们将删除所有当前选定的小于它的数字。我们什么时候可以删除它们,什么时候不能删除它们?

答案 1 :(得分:3)

在最左边的k + 1个数字中,找到最大的一个(假设它位于第i个位置。如果有多个事件,请选择最左边的一个)。收下。重复k_new = k-i + 1,newNumber = i + 1的算法到原始数字的n位数。

Eg. k=5 and number = 7454982641
First k+1 digits: 745498
Best number is 9 and it is located at location i=5. 

new_k=1, new number = 82641
First k+1 digits: 82
Best number is 8 and it is located at i=1.

new_k=1, new number = 2641
First k+1 digits: 26
Best number is 6 and it is located at i=2

new_k=0, new number = 41
Answer: 98641

复杂度为O(n),其中n是输入数字的大小。

编辑:正如iVlad所说,在最坏的情况下,复杂性可能是二次的。你可以通过保持最大k + 1的堆大小来避免这种情况,这会增加O(nlogk)的复杂性。

答案 2 :(得分:1)

以下可能会有所帮助:

void removeNumb(std::vector<int>& v, int k)
{
    if (k == 0) { return; }
    if (k >= v.size()) {
        v.clear();
        return;
    }
    for (int i = 0; i != v.size() - 1; )
    {
        if (v[i] < v[i + 1]) {
            v.erase(v.begin() + i);
            if (--k == 0) { return; }
            i = std::max(i - 1, 0);
        } else {
            ++i;
        }
    }
    v.resize(v.size() - k);
}