Find All Good Strings in C++


Suppose we have two strings s1 and s2. The size of these strings is n, and we also have another string called evil. We have to find the number of good strings.

A string is called good when its size is n, it is alphabetically greater than or equal to s1, it is alphabetically smaller than or equal to s2, and it has no evil as a substring. The answer may be very large, so return the answer modulo 10^9 + 7.

So, if the input is like n = 2, s1 = "bb", s2 = "db", evil = "a", then the output will be 51, as there are 25 good strings that are starting with b. "bb", "bc", "bd", ... "bz", then there are 25 good strings starting with "cb", "cc", "cd",...,"cz", and another good string with d is "db".

To solve this, we will follow these steps −

  • N := 500, M := 50

  • Define an array dp of size: (N+1) x (M+1) x 2.

  • Define an array tr of size: (M+1) x 26.

  • m := 1^9 + 7

  • Define a function add(), this will take a, b,

  • return ((a mod m) + (b mod m)) mod m

  • Define a function solve(), this will take n, s, e,

  • reverse the array e

  • Fill tr and dp with 0

  • for initialize i := 0, when i < size of e, update (increase i by 1), do −

    • f := substring of e from index 0 to i - 1

    • for initialize j := 0, when j < 26, update (increase j by 1), do −

      • ns := f + (j + ASCII of 'a')

      • for initialize k := i + 1, (decrease k by 1), do −

        • if substring of ns from index (i + 1 - k) to end is same as substring of e from index 0 to k-1 of e, then −

          • tr[i, j] := k

          • Come out from the loop

  • m := size of e

  • for initialize i := 0, when i <= n, update (increase i by 1), do −

    • for initialize j := 0, when j < m, update (increase j by 1), do −

      • dp[i, j, 0] := 0

      • dp[i, j, 1] := 0

  • dp[n, 0, 1] := 1

  • for initialize i := n - 1, when i >= 0, update (decrease i by 1), do −

    • for initialize j := 0, when j < size of e, update (increase j by 1), do −

      • for initialize k := 0, when k < 26, update (increase k by 1), do −

        • for l in range (0, 1)

          • if k > s[i] - ASCII of 'a', then −

            • nl := 0

          • otherwise when k < s[i] - ASCII of 'a', then −

            • nl := 1

          • Otherwise

            • nl := l

          • dp[i, tr[j, k], nl] := add(dp[i, tr[j, k], nl], dp[i + 1, j, l])

  • ret := 0

  • for initialize i := 0, when i < size of e, update (increase i by 1), do −

    • ret := add(ret, dp[0, i, 1])

  • return ret

  • From the main method do the following −

  • ok := 1

  • for initialize i := 0, when i < size of s1 and ok is non-zero, update (increase i by 1), do −

    • ok := 1 when s1[i] is same as ASCII of 'a'

  • if not ok is non-zero, then −

    • for initialize i := size of s1, when i >= 0, update (decrease i by 1), do−

      • if s1[i] is not equal to 'a', then −

        • (decrease s1[i] by 1)

        • Come out from the loop

      • s1[i] := ASCII of 'z'

  • left := (if ok is non-zero, then 0, otherwise solve(n, s1, evil))

  • right := solve(n, s2, evil)

  • return (right - left + m) mod m

Let us see the following implementation to get better understanding −

Example

 Live Demo

#include <bits/stdc++.h>
using namespace std;
typedef long long int lli;
const int N = 500;
const int M = 50;
int dp[N + 1][M + 1][2];
int tr[M + 1][26];
const lli m = 1e9 + 7;
class Solution {
   public:
   int add(lli a, lli b){
      return ((a % m) + (b % m)) % m;
   }
   lli solve(int n, string s, string e){
      reverse(e.begin(), e.end());
      memset(tr, 0, sizeof(tr));
      memset(dp, 0, sizeof(dp));
      for (int i = 0; i < e.size(); i++) {
         string f = e.substr(0, i);
         for (int j = 0; j < 26; j++) {
            string ns = f + (char)(j + 'a');
            for (int k = i + 1;; k--) {
               if (ns.substr(i + 1 - k) == e.substr(0, k)) {
                  tr[i][j] = k;
                  break;
               }
            }
         }
      }
      int m = e.size();
      for (int i = 0; i <= n; i++) {
         for (int j = 0; j < m; j++) {
            dp[i][j][0] = dp[i][j][1] = 0;
         }
      }
      dp[n][0][1] = 1;
      for (int i = n - 1; i >= 0; i--) {
         for (int j = 0; j < e.size(); j++) {
            for (int k = 0; k < 26; k++) {
               for (int l : { 0, 1 }) {
                  int nl;
                  if (k > s[i] - 'a') {
                     nl = 0;
                  }
                  else if (k < s[i] - 'a') {
                     nl = 1;
                  }
                  else
                  nl = l;
                  dp[i][tr[j][k]][nl] = add(dp[i][tr[j][k]]
                  [nl], dp[i + 1][j][l]);
               }
            }
         }
      }
      lli ret = 0;
      for (int i = 0; i < e.size(); i++) {
         ret = add(ret, dp[0][i][1]);
      }
      return ret;
   }
   int findGoodStrings(int n, string s1, string s2, string evil) {
      bool ok = 1;
      for (int i = 0; i < s1.size() && ok; i++) {
         ok = s1[i] == 'a';
      }
      if (!ok) {
         for (int i = s1.size() - 1; i >= 0; i--) {
            if (s1[i] != 'a') {
               s1[i]--;
               break;
            }
            s1[i] = 'z';
         }
      }
      int left = ok ? 0 : solve(n, s1, evil);
      int right = solve(n, s2, evil);
      return (right - left + m) % m;
   }
};
main(){
   Solution ob;
   cout << (ob.findGoodStrings(2, "bb", "db", "a"));
}

Input

2, "bb", "db", "a"

Output

51

Updated on: 09-Jun-2020

274 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements