У меня есть два слова, и я хочу получить все перестановки в комбинации этих слов. Относительный порядок символов из каждой строки должен быть сохранен
посмотри на это:
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++?
Работает код (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];..
Я думаю, вы можете сделать это рекурсивно. В основном на каждом шаге вы создаете две ветки: одну, где вы добавляете в свою строку письмо из строки правой стороны, и другую ветвь, в которую вы добавляете первую букву из строки слева:
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);
}
}
Кажется, что вы можете представлять "комбинацию перестановок" по последовательности 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
.
Я опишу подход 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"
Для того, чтобы этот подход работал, вам нужно использовать символы, которые не сталкиваются с вашими исходными входами. Использование вектора отрицательных чисел, например, гарантирует не столкновение с массивом символов и неограниченное количество входных строк...