Check if there exists a permutation of given string which does not contain any monotonous substring


A monotonous substring is a contiguous substring of given string containing characters whose values are all strictly increasing or strictly decreasing. A monotonous substring is a string sequence that either strictly increases or strictly decreases in value.

Method

  • Dynamic Programming

  • Backtracking

Method 1: Dynamic Programming

One technique is to apply dynamic programming to construct table of sub problems, here each item (i, j) in table denotes whether there exists a permutation of the substring S[i...j] that does not contain any monotonous substring. When i=j, the substring comprises only one character and is hence trivially monotonous.

Syntax

Let s be input string of length n, and dp[k][i] be Boolean variable that returns true if permutation of first k characters of s terminates with i-th character and does not contain any monotonous substring.

  • dp[1][i] equals true for all 1 i n.

  • If k > 1 and i > j, dp[k][i] = true if and only if dp[k-1] [j] is true and s[i] is not in the monotonous substring generated by the final two letters of permutation terminating at index j.

The solution to the problem is true if and only if value k exists such that dp[k][i] is true for some 1 i n.

Algorithm

Step 1 − Assume S is n-length input string.

Step 2 − Create two-dimensional Boolean array DP of size n x 2, here DP[i][0] denotes existence of decreasing subsequence ending at the position i and DP[i][1] represents existence of increasing sequence ending at the position i.

Step 3 − Set both DP [0][0] and DP [0][1] to false.

Step 4 − Perform the following for each i from 1 to n-1−

  • Set DP[i][0] to true if there exists a j so that 0 = j i and S[j] > S[i], and DP[j][1] is true.

  • Set DP[i][1] to true if there exists a j so that 0 = j i and S[j] S[i], and DP[j][0] is true.

Step 5 − Determine whether there is point i such that both DP[i][0] and DP[i][1] are true. Return false if such place occurs, indicating there is monotonous substring in permutation.

Step 6 − Otherwise, return true because no monotonous substring exists in any permutation of input string.

Example

To start our approach towards this problem, we first establish a two-dimensional DP matrix titled "dp". In this matrix, each element denotes both ascending and descending characters required for forming strings with length i. Initially in order to set up our matrix correctly for future use, we assign values of 'one' to both elements within cell [1]. Moving forward towards filling up subsequent cells, our recurrence relation uses formulas such as: 'dp[i-1],[0]' for calculating 'dp[[i],[0]]' while 'dp[[i-13,[01'+[j-11,[j41',[i]] generates 'dpi[l,[I],l'. Before employing any further strategy from context herein mentioned however; upon calculating how many times specific characters appear within a given string via [cnt], we consider the concept of whether or not a rearrangement exists, resulting in diminutive/substantial sub-sequence count values less than or equal to "dp[i][0]+dp[i][1]". Receiving a "true" upon assessment verifies the legitimacy of our approaches, while anything else could be deemed as an unsatisfactory output.

#include <iostream>
#include <cstring>
using namespace std;

bool checkMonotonous(string s) {
   int n = s.length();
   int dp[n + 1][2];
   memset(dp, 0, sizeof(dp));
   dp[1][0] = dp[1][1] = 1;
   for (int i = 2; i <= n; i++) {
      dp[i][0] = dp[i - 1][1];
      dp[i][1] = dp[i - 1][0] + dp[i - 1][1];
   }
   int cnt[26] = {0};
   for (int i = 0; i < n; i++) {
      cnt[s[i] - 'a']++;
   }
   for (int i = 1; i <= n; i++) {
      if (dp[i][0] + dp[i][1] > cnt[i - 1]) {
         return false;
      }
   }
   return true;
}

int main() {
   string s = "aabbcc";
   if (checkMonotonous(s)) {
      cout << "There exists a permutation of the given string which doesn't contain any monotonous substring.\n";
   } else {
      cout << "There does not exist permutation of given string which does not contain monotonous substring.\n";
   }
   return 0;
}

Output

There does not exist permutation of given string which does not contain monotonous substring.

Method 2: Backtracking

Backtracking can also be used to generate all possible permutations of the string and then check to see if any of them contain monotonous substrings. This methodology can be delayed for enormous strings because of the great number of changes, however it is ensured to track down an answer if one exists.

Syntax

The general syntax of backtracking in C++ for solving problem of checking permutation of string which does not contain monotonous substring.

bool hasMonotonousSubstring(string s) {
   sort(s.begin(), s.end());
   do {
      bool valid = true;
   for (int i = 2; i < s.length(); i++) {
      if (s[i] == s[i-1] + 1 && s[i-1] == s[i-2] + 1) {
         valid = false;
         break;
      }
      else if (s[i] == s[i-1] - 1 && s[i-1] == s[i-2] - 1) {
         valid = false;
         break;
      }
   }
   if (valid) return true;
   } while (next_permutation(s.begin(), s.end()));
   return false;
}

Algorithm

The generic approach for permutation of given string that does not contain monotonous substring using backtracking in C++ is as follows −

Step 1 − Produce all permutations of supplied string.

Step 2 − Examine each permutation to see if it has any monotonous substrings. If not, the permutation is viable solution.

Step 3 − Return valid solution and end the procedure if one is discovered.

Step 4 − If you've created all potential permutations and none of them are valid, go return to the previous stage and try different candidate solution.

Example 2

The isMonotonous () method determines whether supplied string contains any monotonous substrings or not. It accomplishes this by iterating through text and looking for substrings of length 3 that are either strictly rising or strictly decreasing.

The permute () function generates all permutations of supplied string by backtracking. It takes string s, initial index l, and ending index r as inputs. If initial index equals ending index, we've created permutation. Using isMonotonous () method, we determine whether this permutation contains any monotonous substrings.

The main () function initialises input string and sorts it in lexicographically increasing order. It then calls the permute () function with starting index as 0 and ending index as length of string minus 1. We print "No permutation found" if no monotonous substring-free permutation is found.

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

bool isMonotonous(string s) {
   for (int i = 2; i < s.length(); i++) {
      if ((s[i] > s[i-1] && s[i-1] > s[i-2]) || (s[i] < s[i-1] && s[i-1] < s[i-2])) {
         return true; 
      }
   }
   return false; 
}
bool permute(string s, int l, int r) {
   if (l == r) {
      if (!isMonotonous(s)) {
         cout << s << endl;
         return true;
      }
   }
   else {
      for (int i = l; i <= r; i++) {
         swap(s[l], s[i]);
         if (permute(s, l+1, r)) {
            return true;
         }
         swap(s[l], s[i]);
      }
   }
   return false;
}
int main() {
   string s = "abc";
   sort(s.begin(), s.end()); // sort the string in lexicographically increasing order
   if (!permute(s, 0, s.length()-1)) {
      cout << "No permutation found" << endl;
   }
   return 0;
}

Output

acb

Conclusion

To summarise, determining if given string has permutation that does not contain any monotonous substring is difficult task that necessitates thorough analysis and algorithmic design.

One alternative solution is to generate the possible permutations of string and inspect each one for presence of monotonous substrings. However, because the number of permutations can be quite enormous for big input sizes, this strategy is inefficient.

Updated on: 31-Jul-2023

87 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements