找到小于某个值的最大排列

时间:2018-01-18 02:45:34

标签: c++ string algorithm dynamic-programming

这是一个特定的编程问题,我似乎无法弄明白该怎么做。

  

给定两个整数ab,找到最大的整数   排列a的数字小于b

我可以使用next_permutation中的c++功能吗?或者,我应该使用某种形式的动态编程来解决这个问题吗?

我尝试使用next_permutation函数测试a的所有排列,但因为整数的大小可以达到10 ^ 18,18!这太大了,不可行。 有什么方法可以减少时间吗?如果没有,我应该如何使用动态编程来解决这类问题呢?

我非常感谢为此提供任何帮助。非常感谢你们!

3 个答案:

答案 0 :(得分:3)

为了做到这一点,您无需找到a的所有组合。

我们假设a是'世界',b是'你好'。您可以在a中找到小于或等于b的第一个字符的最大字符。在这种情况下,您会在a中找到“d”。对于a的排列,这是你可以开始的最大角色,所以你应该从它开始。因为'd'严格小于'h',所以你可以将a中所有剩余的字符从最大到最小排序,然后你就得到'dwrol'。

如果第一个字符相同,说a为'世界',b为'喜欢',则在第一个字符后的a中继续执行剩余字符的过程字符并与b的第二个字符进行比较。在此示例中,您在a中选择的第一个字符是“l”。你有'w','o','r','d'。然后你选择一个小于'喜欢'中第二个字符的最大字符,即'd',然后你重复上一个过程并得到'ldwro'。

编辑:

对于编辑过的问题(数字而不是字符的排列),这个想法是一样的。如果a的位数多于b,则a的排列总是大于b(我们假设现在a中没有0)。那么你知道没有解决方案。如果a的位数少于b,则只需查找a的最大排列,因为a永远不会大于b。如果它们具有相同的长度,那么它与按字典顺序进行相同。

如果a中有0,只需将其删除,直到用完0或与b具有相同的位数,然后继续上述过程。

答案 1 :(得分:2)

遍历所有排列将花费太长时间。只是贪婪。

词典比较的情况很简单(这是问题的原始版本):

依次为每个位置选择尚未使用的a的最大元素,仍然使a按字典顺序小于b

数字有点复杂,因为比较数字的规则略有不同。幸运的是,它很容易简化为词典比较。

  • b中删除前导零,这会使事情变得更简单。

  • 如果ab的长度相等,那么它与前一种情况相同 - 词典对比与数字比较相同。

  • 如果b的长度小于a,只需将前导零添加到b以匹配a的长度 - 返回字典比较。

  • 如果a的长度小于b,而b没有前导零(我们只是剥离了它们)。这可以保证a小于b。因此,我们可以通过从最大的第一个开始对数字进行排序来选择最大的排列。

答案 2 :(得分:1)

同意以前的答案 这是一段使用基于std :: set的bag-of-char表示

的代码
#include<iostream>
#include <set>
#include <string>
#include <algorithm>

    std::string greatest_permutation(const std::string &s, const std::string &limit) {
        std::string result;
        std::set<char> bag;
        std::copy(s.begin(), s.end(),
             std::insert_iterator<std::set<char> >(bag, bag.begin()));
        for (int j=0; j<limit.size(); ++j) {
            std::set<char>::iterator i = bag.upper_bound(limit[j]);
            if (i == bag.begin()) // no more chars available
                return result;
            else
                result += *--i;
            bag.erase(i);
        }
    return result;
    }

    int main() {
        std::cout<<
        greatest_permutation("abcdefghi", "cfhuiigwuioiiom")
        <<std::endl;
    }