БлогNot. Все палиндромы строки

Все палиндромы строки

Классическая задачка, но не помню, есть ли она тут, добавим отдельной заметкой.

Дана строка s, требуется разделить её на части так, чтобы каждая отдельная строка была палиндромом (читалась одинаково слева направо и справа налево). Пробелы и другие разделители слов не игнорируются. Строка из одного символа также по определению считается палиндромом.

Нужно вернуть и/или напечатать все возможные палиндромные разбиения s.

Задача проверялась в консоли актуальной сборки Visual Studio 2019.

Решение без рекурсии, O(n2):

#include <iostream>
#include <string>
#include <vector>

bool check_palindrome(std::string s, int index, int i) {
 while (index <= i) {
  if (s[index++] != s[i--]) return 0;
 }
 return 1;
}

void the_helper(std::vector<std::vector<std::string> >& result,
 std::vector<std::string>& dump, std::string s, int n, int index) {
 //избегаем >=, потому что нам нужны только уникальные комбинации
 if (index == n) {
  result.push_back(dump);
  return;
 }
 for (int i = index; i < n; i++) {
  // если s.substr до индекса i является палиндромом
  if (check_palindrome(s, index, i)) {
   dump.push_back(s.substr(index, i - index + 1));
   the_helper(result, dump, s, n, i + 1);
   dump.pop_back(); //задний ход :)
  }
 }
}

int main() {
 std::string s = "amanaplanacanalpanama";
 int n = s.size();
 std::vector<std::vector<std::string>> result; //результаты
 std::vector<std::string> dump; //вектор-дамп, временный
 the_helper(result, dump, s, n, 0);
 int row_l = result.size();
 std::cout << "All Possible palindromic partitions of string" << std::endl;
 std::cout << "[";
 for (int i = 0; i < row_l; i++) {
  std::cout << "[" << (i + 1) << ": ";
  int m = result[i].size();
  for (int j = 0; j < m; j++) {
   if (j == m - 1) {
    std::cout << result[i][j];
    continue;
   }
   std::cout << result[i][j] << ",";
  }
  if (i == row_l - 1) {
   std::cout << "]";
   continue;
  }
  std::cout << "],";
 }
 std::cout << "]";
 return 0;
}

Решение с рекурсией.

#include <iostream>
#include <string>
#include <vector>

bool checkPalindrome(std::string str) { //палиндром или нет
 int len = str.length() - 1;
 for (int i = 0; i < len; i++) {
  if (str[i] != str[len]) return false;
  len--;
 }
 return true;
}

void printSolution(std::vector<std::vector<std::string>> partitions) {
 for (int i = 0; i < partitions.size(); ++i) {
  std::cout << (i+1) << ") ";
  for (int j = 0; j < partitions[i].size(); ++j)
   std::cout << partitions[i][j] << " ";
  std::cout << std::endl;
 }
 return;
}

//Проходим по всем индексам и рекурсивно добавляем оставшиеся
//части, если текущая std::string является палиндромом.
void addStrings(std::vector<std::vector<std::string> >& v, std::string& s,
 std::vector<std::string>& temp, int index) {
 int len = s.length();
 std::string str;
 std::vector<std::string> current = temp;
 if (index == 0) temp.clear();
 for (int i = index; i < len; ++i) {
  str = str + s[i];
  if (checkPalindrome(str)) {
   temp.push_back(str);
   if (i + 1 < len) addStrings(v, s, temp, i + 1);
   else v.push_back(temp);
   temp = current;
  }
 }
 return;
}

void partition(std::string s, std::vector<std::vector<std::string>> &v) {
 //Генерирует все палиндромы из s и сохраняет результат в v
 std::vector<std::string> temp;
 addStrings(v, s, temp, 0);
 return;
}

int main() {
 std::string s = "amanaplanacanalpanama";
 std::vector<std::vector<std::string> > partitions;
 partition (s, partitions);
 printSolution (partitions);
 return 0;
}

В обоих случаях получилось по 92 разбиения. И помните - итерация и рекурсия взаимозаменяемы всегда.

04.02.2023, 14:43 [306 просмотров]


теги: c++ алгоритм textprocessing

К этой статье пока нет комментариев, Ваш будет первым