找到一些字符串的字典排列最小的排列

时间:2016-09-22 09:26:28

标签: c++ algorithm permutation breadth-first-search

标题可能看起来好像是一个非常常见的问题,但请耐心等待。

基本上可以说在字符串的每个索引处,您知道哪些字母可以在该索引中,然后您希望找到按字典顺序排列的最小排列。

例如:

Index  |  Options
-------|----------
  1    |  'b'
  2    |  'c', 'a'
  3    |  'd', 'c'
  4    |  'c', 'a'

因此,o / p应为badc。是的顺便说一句,字符不能重复,所以没有贪心算法。

我认为我们可以通过创建队列或字符串的某些东西来使用某种广度优先搜索,每当我们发现我们无法创建另一个排列时,就会将其从列表中弹出。怀疑这是最佳的,必须是O(N)中的某些东西。有什么想法吗?

不,我不认为C很糟糕,但我更喜欢C / C ++中的代码片段:p

谢谢!

2 个答案:

答案 0 :(得分:4)

这可以通过匹配算法来解决。您可以使用网络流解决方案来解决此问题。这可以分解为双分图问题。

准确地说,最大权重分配问题或最大成本最大匹配将是一种解决方案。

下面是二分顶点集 -

#ifndef _DIRECTCONDITIONALS_HPP
#define _DIRECTCONDITIONALS_HPP
#include"snakeGame.hpp"

class DirectConditions{
    public:
        class SnakeGame;
        virtual void goToDirection(SnakeGame&)=0;
        virtual ~DirectConditions(){};
};

class GoRight:public DirectConditions{
    public:
        void goToDirection(SnakeGame& snakeObj){
            snakeObj.snake[0].xCoor+=1;
        }
};

class GoLeft:public DirectConditions{
    public:
        void goToDirection(SnakeGame& snakeObj){
            snakeObj.snake[0].xCoor-=1;
        }
};

class GoUp:public DirectConditions{
    public:
        void goToDirection(SnakeGame& snakeObj){
            snakeObj.snake[0].yCoor+=1;
        }
};

class GoDown:public DirectConditions{
    public:
        void goToDirection(SnakeGame& snakeObj){
            snakeObj.snake[0].yCoor-=1;
        }
};

#endif

现在将“设置级别”中的边指定为“仅字母”,仅当这些是该级别的选项时。所以这些将是边缘 - {1,b},{2,a},{2,c},{3,c},{3,d},{4,a},{4,c} 现在,要获得按字典顺序排列的最小结果,您需要以这种方式为边缘分配权重 -

LEVEL          Alphabets
 1                 a  
 2                 b
 3                 c
 4                 d
                   e
                   .
                   .
                   .
                   z 

因此,例如边{2,c}的边权重

Edge Wt. = 26^(N-Level) * ('z' - Alphabet)

现在您可以使用标准的最高成本最大匹配解决方案。哪个是多项式解。就我现在的想法而言,这将是最好的方法。天真的解决方案是指数解26 ^ N,所以我认为你会对多项式解决方案感到满意。

答案 1 :(得分:0)

天真的方法是使用回溯并尝试所有可能的解决方案,但它不够有效(26!)。然后,您可以通过在位掩码的帮助下使用动态编程来改进此回溯解决方案。位掩码可以帮助您存储到目前为止使用的字符。

写一个递归函数,它接受两个输入,应该为其指定一个字符的索引,以及一个指示我们到目前为止使用了哪些字符的位掩码。最初位掩码包含26个零,这意味着我们没有使用任何字符。在为某个索引分配字符后,我们相应地更改了位掩码。例如,如果我们使用字符 a ,我们将位掩码的第一位设置为1.这样你就不会解决很多重叠的子问题。

#include <iostream>
#include <queue>
#include <vector>
#include <map>
using namespace std;

vector<vector<char> > data;
map< pair<int,int>, string > dp;

string func( int index, int bitmask ){
    pair<int,int> p = make_pair(index,bitmask);
    if ( dp.count( p ) )
        return dp[p];
    string min_str = "";
    for ( int i=0; i<data[index].size(); ++i ){
        if ( (bitmask&(1<<(data[index][i]-'a'))) == 0 ){
            string cur_str = "";
            cur_str += data[index][i];
            if ( index+1 != data.size() ){
                int mask = bitmask;
                mask |= 1<<(data[index][i]-'a');
                string sub = func(index+1, mask);
                if (sub == "")
                    continue;    
                cur_str += sub;
            }
            if ( min_str == "" || cur_str < min_str ){
                min_str = cur_str;
            }
        }
    }
    dp[p] = min_str;
    return min_str;
}


int main()
{
    data.resize(4);
    data[0].push_back('b');
    data[1].push_back('c');
    data[1].push_back('a');
    data[2].push_back('d');
    data[2].push_back('c');
    data[3].push_back('c');
    data[3].push_back('a');
    cout << func(0,0) << endl;
}