Open In App

Count number of ways to convert string S to T by performing K cyclic shifts

Improve
Improve
Like Article
Like
Save
Share
Report

Given two strings S and T and a number K, the task is to count the number of ways to convert string S to string T by performing K cyclic shifts
 

The cyclic shift is defined as the string S can be split into two non-empty parts X + Y and in one operation we can transform S to Y + X from X + Y.


Note: Since count can be very large print the answer to modulo 109 + 7.
Examples: 
 

Input: S = “ab”, T = “ab”, K = 2 
Output:
Explanation: 
The only way to do this is to convert [ab to ba] in the first move and then [ba to ab] in the second move. 
Input: S = “ababab”, T = “ababab”, K = 1 
Output:
Explanation: 
One possible way to convert S to T in one move is [ab | abab] -> [ababab], the second way is [abab | ab] -> [ababab]. So there are total two ways. 
 


 


Approach: This problem can be solved using Dynamic Programming. Let us call a cyclic shift ‘good’ if at the end we are at string T and the vice versa for ‘bad’. Below are the steps:
 

  1. Precompute the number of good(denoted by a) and bad(denoted by b) cyclic shifts.
  2. Initialize two dp arrays such that dp1[i] denote the number of ways to get to a good shift in i moves and dp2[i] denotes the number of ways to get to a bad shift in i moves.
  3. For transition, we are only concerned about previous state i.e., (i – 1)th state and the answer to this question is dp1[K].
  4. So the number of ways to reach a good state in i moves is equal to the number of ways of reaching a good shift in i-1 moves multiplied by (a-1) (as last shift is also good)
  5. So the number of ways of reaching a bad shift in i-1 moves multiplied by (a)(as next move can be any of the good shifts).


Below is the recurrence relation for the good and bad shifts:
 

So for good shifts we have: 
dp1[i]= dp1[i-1]*(a-1) + dp2[i-1]*a
Similarly, for bad shifts we have: 
dp2[i]=dp1[i-1]*b + dp2[i-1]*(b-1)
 


Below is the implementation of above approach: 
 

C++

// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
#define mod 10000000007
 
// Function to count number of ways to
// convert string S to string T by
// performing K cyclic shifts
long long countWays(string s, string t,
                    int k)
{
    // Calculate length of string
    int n = s.size();
 
    // 'a' is no of good cyclic shifts
    // 'b' is no of bad cyclic shifts
    int a = 0, b = 0;
 
    // Iterate in the string
    for (int i = 0; i < n; i++) {
 
        string p = s.substr(i, n - i)
                + s.substr(0, i);
 
        // Precompute the number of good
        // and bad cyclic shifts
        if (p == t)
            a++;
        else
            b++;
    }
 
    // Initialize two dp arrays
    // dp1[i] to store the no of ways to
    // get to a good shift in i moves
 
    // dp2[i] to store the no of ways to
    // get to a bad shift in i moves
    vector<long long> dp1(k + 1), dp2(k + 1);
 
    if (s == t) {
        dp1[0] = 1;
        dp2[0] = 0;
    }
    else {
        dp1[0] = 0;
        dp2[0] = 1;
    }
 
    // Calculate good and bad shifts
    for (int i = 1; i <= k; i++) {
 
        dp1[i]
            = ((dp1[i - 1] * (a - 1)) % mod
            + (dp2[i - 1] * a) % mod)
            % mod;
 
        dp2[i]
            = ((dp1[i - 1] * (b)) % mod
            + (dp2[i - 1] * (b - 1)) % mod)
            % mod;
    }
 
    // Return the required number of ways
    return dp1[k];
}
 
// Driver Code
int main()
{
    // Given Strings
    string S = "ab", T = "ab";
 
    // Given K shifts required
    int K = 2;
 
    // Function Call
    cout << countWays(S, T, K);
    return 0;
}

                    

Java

// Java program for above approach
class GFG{
     
static long mod = 10000000007L;
 
// Function to count number of ways to
// convert string S to string T by
// performing K cyclic shifts
static long countWays(String s, String t,
                    int k)
{
     
    // Calculate length of string
    int n = s.length();
 
    // 'a' is no of good cyclic shifts
    // 'b' is no of bad cyclic shifts
    int a = 0, b = 0;
 
    // Iterate in the string
    for(int i = 0; i < n; i++)
    {
    String p = s.substring(i, n - i) +
                s.substring(0, i);
         
    // Precompute the number of good
    // and bad cyclic shifts
    if (p == t)
        a++;
    else
        b++;
    }
 
    // Initialize two dp arrays
    // dp1[i] to store the no of ways to
    // get to a good shift in i moves
 
    // dp2[i] to store the no of ways to
    // get to a bad shift in i moves
    long dp1[] = new long[k + 1];
    long dp2[] = new long[k + 1];
 
    if (s == t)
    {
        dp1[0] = 1;
        dp2[0] = 0;
    }
    else
    {
        dp1[0] = 0;
        dp2[0] = 1;
    }
 
    // Calculate good and bad shifts
    for(int i = 1; i <= k; i++)
    {
    dp1[i] = ((dp1[i - 1] * (a - 1)) % mod +
                (dp2[i - 1] * a) % mod) % mod;
    dp2[i] = ((dp1[i - 1] * (b)) % mod +
                (dp2[i - 1] * (b - 1)) % mod) % mod;
    }
 
    // Return the required number of ways
    return dp1[k];
}
 
// Driver code
public static void main(String[] args)
{
     
    // Given Strings
    String S = "ab", T = "ab";
 
    // Given K shifts required
    int K = 2;
 
    // Function Call
    System.out.print(countWays(S, T, K));
}
}
 
// This code is contributed by Pratima Pandey

                    

Python3

# Python3 program for the above approach
mod = 1000000007
 
# Function to count number of ways
# to convert string S to string T by
# performing K cyclic shifts
def countWays(s, t, k):
     
    # Calculate length of string
    n = len(s)
     
    # a is no. of good cyclic shifts
    # b is no. of bad cyclic shifts
    a = 0
    b = 0
     
    # Iterate in string
    for i in range(n):
        p = s[i : ] + s[: i]
         
        # Precompute the number of good
        # and bad cyclic shifts
        if(p == t):
            a += 1
        else:
            b += 1
             
    # Initialize two dp arrays
    # dp1[i] to store the no of ways to
    # get to a goof shift in i moves
     
    # dp2[i] to store the no of ways to
    # get to a bad shift in i moves
    dp1 = [0] * (k + 1)
    dp2 = [0] * (k + 1)
     
    if(s == t):
        dp1[0] = 1
        dp2[0] = 0
    else:
        dp1[0] = 0
        dp2[0] = 1
         
    # Calculate good and bad shifts    
    for i in range(1, k + 1):
        dp1[i] = ((dp1[i - 1] * (a - 1)) % mod +
                (dp2[i - 1] * a) % mod) % mod
 
        dp2[i] = ((dp1[i - 1] * (b)) % mod +
                (dp2[i - 1] * (b - 1)) % mod) % mod
                     
    # Return the required number of ways
    return(dp1[k])
     
# Driver Code
 
# Given Strings
S = 'ab'
T = 'ab'
 
# Given K shifts required
K = 2
 
# Function call
print(countWays(S, T, K))
 
# This code is contributed by Arjun Saini

                    

C#

// C# program for the above approach
using System;
 
class GFG{
     
static long mod = 10000000007L;
 
// Function to count number of ways to
// convert string S to string T by
// performing K cyclic shifts
static long countWays(string s, string t,
                      int k)
{
     
    // Calculate length of string
    int n = s.Length;
 
    // 'a' is no of good cyclic shifts
    // 'b' is no of bad cyclic shifts
    int a = 0, b = 0;
 
    // Iterate in the string
    for(int i = 0; i < n; i++)
    {
        string p = s.Substring(i, n - i) +
                   s.Substring(0, i);
         
        // Precompute the number of good
        // and bad cyclic shifts
        if (p == t)
            a++;
        else
            b++;
    }
 
    // Initialize two dp arrays
    // dp1[i] to store the no of ways to
    // get to a good shift in i moves
 
    // dp2[i] to store the no of ways to
    // get to a bad shift in i moves
    long []dp1 = new long[k + 1];
    long []dp2 = new long[k + 1];
 
    if (s == t)
    {
        dp1[0] = 1;
        dp2[0] = 0;
    }
    else
    {
        dp1[0] = 0;
        dp2[0] = 1;
    }
 
    // Calculate good and bad shifts
    for(int i = 1; i <= k; i++)
    {
        dp1[i] = ((dp1[i - 1] * (a - 1)) % mod +
                  (dp2[i - 1] * a) % mod) % mod;
        dp2[i] = ((dp1[i - 1] * (b)) % mod +
                  (dp2[i - 1] * (b - 1)) % mod) % mod;
    }
 
    // Return the required number of ways
    return dp1[k];
}
 
// Driver code
public static void Main(string[] args)
{
     
    // Given Strings
    string S = "ab", T = "ab";
 
    // Given K shifts required
    int K = 2;
 
    // Function call
    Console.Write(countWays(S, T, K));
}
}
 
// This code is contributed by rutvik_56

                    

Javascript

<script>
 
// JavaScript program for the above approach
 
let mod = 10000000007;
 
// Function to count number of ways to
// convert string S to string T by
// performing K cyclic shifts
function countWays(s, t, k)
{
     
    // Calculate length of string
    let n = s.length;
 
    // 'a' is no of good cyclic shifts
    // 'b' is no of bad cyclic shifts
    let a = 0, b = 0;
 
    // Iterate in the string
    for(let i = 0; i < n; i++)
    {
    let p = s.substr(i, n - i) +
                s.substr(0, i);
         
    // Precompute the number of good
    // and bad cyclic shifts
    if (p == t)
        a++;
    else
        b++;
    }
 
    // Initialize two dp arrays
    // dp1[i] to store the no of ways to
    // get to a good shift in i moves
 
    // dp2[i] to store the no of ways to
    // get to a bad shift in i moves
    let dp1 = Array.from({length: k+1}, (_, i) => 0);
    let dp2 = Array.from({length: k+1}, (_, i) => 0);
 
    if (s == t)
    {
        dp1[0] = 1;
        dp2[0] = 0;
    }
    else
    {
        dp1[0] = 0;
        dp2[0] = 1;
    }
 
    // Calculate good and bad shifts
    for(let i = 1; i <= k; i++)
    {
    dp1[i] = ((dp1[i - 1] * (a - 1)) % mod +
                (dp2[i - 1] * a) % mod) % mod;
    dp2[i] = ((dp1[i - 1] * (b)) % mod +
                (dp2[i - 1] * (b - 1)) % mod) % mod;
    }
 
    // Return the required number of ways
    return dp1[k];
}
 
// Driver Code
 
    // Given Strings
    let S = "ab", T = "ab";
 
    // Given K shifts required
    let K = 2;
 
    // Function Call
    document.write(countWays(S, T, K));
 
</script>

                    

Output
1


Time Complexity: O(N) 
Auxiliary Space: O(K)
 

Efficient approach: Space optimization O(1)

In the previous approach, the current values dp1[i]  and dp2[i] only depend upon the previous value i.e. dp1[i-1] and dp2[i-1]. So to optimize the space we can keep track of previous and current values with the help of 2 variables prev and curr which will reduce the space complexity from O(k) to O(1).  

Steps to implement the above approach:

  • Create 2 variables for both array dp1_prev and dp2_prev to keep track o previous values of dp1 and dp2.
  • Initialize base case dp1_prev and dp2_prev.
  • Create a variable current for both dp1_curr and dp2_curr to store the current value.
  • Iterate over the subproblem using a loop and update both current values.
  • After every iteration update dp1_prev and dp2_prev for further iterations.
  • At last return dp1_curr.

Below is the code to implement the above approach:

C++

// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
#define mod 10000000007
 
// Function to count number of ways to
// convert string S to string T by
// performing K cyclic shifts
long long countWays(string s, string t, int k)
{
    // Calculate length of string
    int n = s.size();
 
    // 'a' is no of good cyclic shifts
    // 'b' is no of bad cyclic shifts
    int a = 0, b = 0;
 
    // Iterate in the string
    for (int i = 0; i < n; i++) {
 
        string p = s.substr(i, n - i) + s.substr(0, i);
 
        // Precompute the number of good
        // and bad cyclic shifts
        if (p == t)
            a++;
        else
            b++;
    }
 
    // initialize variables for current and previous values
    // of DP1 and DP2
    int dp1_curr, dp1_prev, dp2_curr, dp2_prev;
 
    // Base Case
    if (s == t) {
        dp1_prev = 1;
        dp2_prev = 0;
    }
    else {
        dp1_prev = 0;
        dp2_prev = 1;
    }
 
    // Iterate over subproblems and update current values
    for (int i = 1; i <= k; i++) {
 
        dp1_curr = ((dp1_prev * (a - 1)) % mod
                    + (dp2_prev * a) % mod)
                   % mod;
 
        dp2_curr = ((dp1_prev * (b)) % mod
                    + (dp2_prev * (b - 1)) % mod)
                   % mod;
 
        // assigning values for iterating further
        dp1_prev = dp1_curr;
        dp2_prev = dp2_curr;
    }
 
    // return final answer
    return dp1_curr;
}
 
// Driver Code
int main()
{
    // Given Strings
    string S = "ab", T = "ab";
 
    // Given K shifts required
    int K = 2;
 
    // Function Call
    cout << countWays(S, T, K);
    return 0;
}

                    

Java

import java.util.*;
 
public class Main {
    static long mod = 10000000007L;
 
    public static long countWays(String s, String t, int k) {
        // Calculate length of string
        int n = s.length();
 
        // 'a' is no of good cyclic shifts
        // 'b' is no of bad cyclic shifts
        int a = 0, b = 0;
 
        // Iterate in the string
        for (int i = 0; i < n; i++) {
            String p = s.substring(i, n) + s.substring(0, i);
 
            // Precompute the number of good
            // and bad cyclic shifts
            if (p.equals(t))
                a++;
            else
                b++;
        }
 
        // initialize variables for current and previous values
        // of DP1 and DP2
        long dp1_curr = 0, dp1_prev, dp2_curr = 0, dp2_prev;
 
        // Base Case
        if (s.equals(t)) {
            dp1_prev = 1;
            dp2_prev = 0;
        } else {
            dp1_prev = 0;
            dp2_prev = 1;
        }
 
        // Iterate over subproblems and update current values
        for (int i = 1; i <= k; i++) {
            dp1_curr = ((dp1_prev * (a - 1)) % mod
                    + (dp2_prev * a) % mod)
                    % mod;
 
            dp2_curr = ((dp1_prev * b) % mod
                    + (dp2_prev * (b - 1)) % mod)
                    % mod;
 
            // assigning values for iterating further
            dp1_prev = dp1_curr;
            dp2_prev = dp2_curr;
        }
 
        // return final answer
        return dp1_curr;
    }
 
    public static void main(String[] args) {
        // Given Strings
        String S = "ab", T = "ab";
 
        // Given K shifts required
        int K = 2;
 
        // Function Call
        System.out.println(countWays(S, T, K));
    }
}

                    

Python3

MOD = 10**9 + 7  # Define a constant for modulo arithmetic
 
def countWays(s, t, k):
    n = len(s)
    a, b = 0, 0  # Initialize counts of good and bad cyclic shifts
 
    # Iterate over all cyclic shifts of s and count good and bad ones
    for i in range(n):
        p = s[i:] + s[:i]  # Compute the i-th cyclic shift of s
 
        if p == t:
            a += 1
        else:
            b += 1
 
    # Initialize variables for DP
    dp1_prev, dp2_prev = (1, 0) if s == t else (0, 1)
    dp1_curr, dp2_curr = 0, 0
 
    # Iterate over subproblems and update DP values
    for i in range(1, k+1):
        dp1_curr = ((dp1_prev * (a - 1)) % MOD + (dp2_prev * a) % MOD) % MOD
        dp2_curr = ((dp1_prev * b) % MOD + (dp2_prev * (b - 1)) % MOD) % MOD
 
        # Update previous values for next iteration
        dp1_prev, dp2_prev = dp1_curr, dp2_curr
 
    return dp1_curr
 
# Example usage
S = 'ab'
T = 'ab'
K = 2
 
print(countWays(S, T, K))

                    

C#

using System;
 
public class MainClass {
  static long mod = 10000000007L;
 
  public static long countWays(string s, string t, int k)
  {
     
    // Calculate length of string
    int n = s.Length;
 
    // 'a' is no of good cyclic shifts
    // 'b' is no of bad cyclic shifts
    int a = 0, b = 0;
 
    // Iterate in the string
    for (int i = 0; i < n; i++) {
      string p = s.Substring(i, n - i) + s.Substring(0, i);
 
      // Precompute the number of good
      // and bad cyclic shifts
      if (p.Equals(t))
        a++;
      else
        b++;
    }
 
    // initialize variables for current and previous values
    // of DP1 and DP2
    long dp1_curr = 0, dp1_prev, dp2_curr = 0, dp2_prev;
 
    // Base Case
    if (s.Equals(t)) {
      dp1_prev = 1;
      dp2_prev = 0;
    } else {
      dp1_prev = 0;
      dp2_prev = 1;
    }
 
    // Iterate over subproblems and update current values
    for (int i = 1; i <= k; i++) {
      dp1_curr = ((dp1_prev * (a - 1)) % mod
                  + (dp2_prev * a) % mod)
        % mod;
 
      dp2_curr = ((dp1_prev * b) % mod
                  + (dp2_prev * (b - 1)) % mod)
        % mod;
 
      // assigning values for iterating further
      dp1_prev = dp1_curr;
      dp2_prev = dp2_curr;
    }
 
    // return final answer
    return dp1_curr;
  }
 
  public static void Main()
  {
     
    // Given Strings
    string S = "ab", T = "ab";
 
    // Given K shifts required
    int K = 2;
 
    // Function Call
    Console.WriteLine(countWays(S, T, K));
  }
}

                    

Javascript

// Define a constant for modulo arithmetic
const MOD = 1000000007;
 
function countWays(s, t, k) {
    const n = s.length;
     
    // Initialize counts of good and bad cyclic shifts
    let a = 0, b = 0;
 
    // Iterate over all cyclic shifts of s and count good and bad ones
    for (let i = 0; i < n; i++) {
     
        // Compute the i-th cyclic shift of s
        const p = s.slice(i) + s.slice(0, i);
 
        if (p === t) {
            a += 1;
        } else {
            b += 1;
        }
    }
 
    // Initialize variables for DP
    let dp1_prev, dp2_prev;
     
    if (s === t) {
        dp1_prev = 1;
        dp2_prev = 0;
    } else {
        dp1_prev = 0;
        dp2_prev = 1;
    }
 
    let dp1_curr = 0, dp2_curr = 0;
 
    // Iterate over subproblems and update DP values
    for (let i = 1; i <= k; i++) {
     
        dp1_curr = ((dp1_prev * (a - 1)) % MOD + (dp2_prev * a) % MOD) % MOD;
        dp2_curr = ((dp1_prev * b) % MOD + (dp2_prev * (b - 1)) % MOD) % MOD;
 
        // Update previous values for the next iteration
        dp1_prev = dp1_curr;
        dp2_prev = dp2_curr;
    }
 
    return dp1_curr;
}
 
// Example usage
const S = 'ab';
const T = 'ab';
const K = 2;
 
console.log(countWays(S, T, K));
 
// This code is contributed by Samim Hossain Mondal.

                    

Output

1

Time Complexity: O(N) 
Auxiliary Space: O(1)



Last Updated : 02 Nov, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads