Find All Good Strings in C++

C++Server Side ProgrammingProgramming

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
raja
Published on 09-Jun-2020 07:11:15
Advertisements