как получить всю комбинацию перестановок из двух строк?

0

У меня есть два слова, и я хочу получить все перестановки в комбинации этих слов. Относительный порядок символов из каждой строки должен быть сохранен

посмотри на это:

Input= "abc", "mn"

Output= "abcmn", "abmnc", "amnbc", "mnabc", "mabcn", "manbc", "mabnc", "ambnc", "ambcn", "abmcn"

Я ищу stackoverflow.com и получаю следующий код, но он не работает!

void print_towstring(const std::vector<int>& v, const std::string& s1, const std::string& s2)
{
    std::size_t i1 = 0;
    std::size_t i2 = 0;

    for (int i : v) {
        std::cout << ((i == 0) ? s1[i1++] : s2[i2++]);
    }
    std::cout << std::endl;
}

void towstring(const std::string& s1, const std::string& s2)
{
    std::vector<int> v(s1.size(), 0);

    v.insert(v.end(), s2.size(), 1);
    do
    {
        print_towstring(v, s1, s2);
    } while (std::next_permutation(v.begin(), v.end()));
}

int main(int argc, char *argv[])
{
    towstring("abc", "mn");
    return 0;
}

как я могу написать алгоритм перестановочной комбинации в c++?

  • 1
    Я только заметил, что ваш вопрос похож на этот . Вы ребята в одном классе?
  • 0
    да, и я видел этот вопрос, прежде чем задавать. но этот вопрос мне совсем не помогает!
Показать ещё 5 комментариев
Теги:
string
algorithm

4 ответа

2

Работает код (My): http://ideone.com/IYYVZY

Он просто использует С++ 11. для С++ 03 см. http://ideone.com/ZHXSkt

Вы должны изменить цикл для диапазона

for (int e: v)for (std::size_t я = 0, size = v.size(); я != size; ++i) { int e = v[i];.. for (std::size_t я = 0, size = v.size(); я != size; ++i) { int e = v[i];..

  • 0
    Хороший алгоритм!
2

Я думаю, вы можете сделать это рекурсивно. В основном на каждом шаге вы создаете две ветки: одну, где вы добавляете в свою строку письмо из строки правой стороны, и другую ветвь, в которую вы добавляете первую букву из строки слева:

    void AddNext(
      std::string const& left,
      std::string const& right,
      std::string const& current,
      std::vector< std::string >& results)
    {
      if (left.empty())
      {
        current.append(right);
        results.push_back(current);
        return;
      }
      else if (right.empty())
      {
         current.append(left);
         results.push_back(current)
         return;
      }
      else
      {
        AddNext(left, right.substr(1, right.size() -1), current + std::string(1, right[0]), results);
        AddNext(left.substr(1, left.size() -1), right, current + std::string(1, left[0]), results);
      }
}
2

Кажется, что вы можете представлять "комбинацию перестановок" по последовательности 0 и 1, где каждое число указывает, из какой строки следует следующий символ, например:

00101 - means abmcn

Итак, теперь вам нужно создать все такие строки, которые имеют заданное число 0 и заданное число 1 (3 и 2 в вашем примере). Для этого, я думаю, самым простым было бы перебрать все комбинации 0 и 1 и выбросить те, у которых не было необходимого количества 1.

Мне нравится представлять строку битов числом, начиная с младшего значащего бита, например, 00101 соответствует

0 * 2^0 +
0 * 2^1 +
1 * 2^2 +
0 * 2^3 +
1 * 2^4 = 20

(предупреждение: это будет работать только для ограниченного размера строки - до 32 - или любого количества битов int. Для более длинных строк реализация может быть адаптирована к 64 битам, но это не стоит, потому что она будет слишком медленной так или иначе)

Чтобы получить заданный бит от такого числа:

int GetBit(int n, int b)
{
    return (n >> b) & 1;
}

Чтобы преобразовать такое число в вектор:

void ConvertNumberToVector(int n, std::vector<int>& v)
{
    for (int b = 0; b < v.size(); ++b)
        v[b] = GetBit(n, b);
}

Затем вы можете использовать этот вектор с функцией print_towstring.

  • 0
    +1 для сопоставления ввода. Учителя дадут вам пять очков, если вы придете с таким подходом ... Он может быть масштабирован до произвольного числа входов. Можете ли вы просто объяснить это немного лучше, пожалуйста?
  • 0
    Вероятно, вы можете просто написать std :: vector <bool> со значением 00011 и затем сгенерировать все его перестановки. Затем напишите что-нибудь, что сгенерирует строку из этих перестановок. Это решило бы проблему наличия комбинаций, которые не соответствуют размеру входной строки.
Показать ещё 1 комментарий
1

Я опишу подход anatolyg, чтобы обеспечить решение для n входных строк, скажем, для простоты n <=10 (см., Куда я иду?). Обратите внимание, как относительный порядок для одной строки никогда не изменяется? Это основа алгоритма

step1: Вы берете свою строку в массиве или векторе или что угодно. для каждой строки вы назначаете символ размера один, например, символ 0 для первого, 1 для второго, до 9.

шаги 2: у вас есть функция, которая преобразует входные данные в одну строку (или лучше вектор), где каждый символ находится из исходной строки. В вашем случае функция:

 f("abc", "mn") => "00011"

шаги 3: вы перечисляете перестановки над результирующей строкой, в данном случае "00011". Вы уже были на правильном пути с помощью std::next_permutation()

шаги4: вы повторяете каждую из полученной строки и используете ее символ в качестве маски. что-то вроде

void mergewithmask(std::string& target, std::string& input, char mask )
{
 int i = 0;//target index
 int j = 0;//input index
 for(i = 0; i < target.size(); i++)
 {
   if(target[i] == mask){
      target[i] = input[j];
      j++;
   }
 }
}

так

mergewithmask("01001","abc", '0') => "a1bc1"
mergewithmask("a1bc1","mn", '1') => "ambcn"

Для того, чтобы этот подход работал, вам нужно использовать символы, которые не сталкиваются с вашими исходными входами. Использование вектора отрицательных чисел, например, гарантирует не столкновение с массивом символов и неограниченное количество входных строк...

Ещё вопросы

Сообщество Overcoder
Наверх
Меню