Overflow in intermediate arithmetic
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
You are given two strings s and t of equal length n. You can perform the following operation on the string s:
s of length l where 0 < l < n and append it at the start of s.s = 'abcd' then in one operation you can remove the suffix 'cd' and append it in front of s making s = 'cdab'.You are also given an integer k. Return the number of ways in which s can be transformed into t in exactly k operations.
Since the answer can be large, return it modulo 109 + 7.
Example 1:
Input: s = "abcd", t = "cdab", k = 2 Output: 2 Explanation: First way: In first operation, choose suffix from index = 3, so resulting s = "dabc". In second operation, choose suffix from index = 3, so resulting s = "cdab". Second way: In first operation, choose suffix from index = 1, so resulting s = "bcda". In second operation, choose suffix from index = 1, so resulting s = "cdab".
Example 2:
Input: s = "ababab", t = "ababab", k = 1 Output: 2 Explanation: First way: Choose suffix from index = 2, so resulting s = "ababab". Second way: Choose suffix from index = 4, so resulting s = "ababab".
Constraints:
2 <= s.length <= 5 * 1051 <= k <= 1015s.length == t.lengths and t consist of only lowercase English alphabets.Problem summary: You are given two strings s and t of equal length n. You can perform the following operation on the string s: Remove a suffix of s of length l where 0 < l < n and append it at the start of s. For example, let s = 'abcd' then in one operation you can remove the suffix 'cd' and append it in front of s making s = 'cdab'. You are also given an integer k. Return the number of ways in which s can be transformed into t in exactly k operations. Since the answer can be large, return it modulo 109 + 7.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Math · Dynamic Programming · String Matching
"abcd" "cdab" 2
"ababab" "ababab" 1
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2851: String Transformation
class Solution {
private static final int M = 1000000007;
private int add(int x, int y) {
if ((x += y) >= M) {
x -= M;
}
return x;
}
private int mul(long x, long y) {
return (int) (x * y % M);
}
private int[] getZ(String s) {
int n = s.length();
int[] z = new int[n];
for (int i = 1, left = 0, right = 0; i < n; ++i) {
if (i <= right && z[i - left] <= right - i) {
z[i] = z[i - left];
} else {
int z_i = Math.max(0, right - i + 1);
while (i + z_i < n && s.charAt(i + z_i) == s.charAt(z_i)) {
z_i++;
}
z[i] = z_i;
}
if (i + z[i] - 1 > right) {
left = i;
right = i + z[i] - 1;
}
}
return z;
}
private int[][] matrixMultiply(int[][] a, int[][] b) {
int m = a.length, n = a[0].length, p = b[0].length;
int[][] r = new int[m][p];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < p; ++j) {
for (int k = 0; k < n; ++k) {
r[i][j] = add(r[i][j], mul(a[i][k], b[k][j]));
}
}
}
return r;
}
private int[][] matrixPower(int[][] a, long y) {
int n = a.length;
int[][] r = new int[n][n];
for (int i = 0; i < n; ++i) {
r[i][i] = 1;
}
int[][] x = new int[n][n];
for (int i = 0; i < n; ++i) {
System.arraycopy(a[i], 0, x[i], 0, n);
}
while (y > 0) {
if ((y & 1) == 1) {
r = matrixMultiply(r, x);
}
x = matrixMultiply(x, x);
y >>= 1;
}
return r;
}
public int numberOfWays(String s, String t, long k) {
int n = s.length();
int[] dp = matrixPower(new int[][] {{0, 1}, {n - 1, n - 2}}, k)[0];
s += t + t;
int[] z = getZ(s);
int m = n + n;
int result = 0;
for (int i = n; i < m; ++i) {
if (z[i] >= n) {
result = add(result, dp[i - n == 0 ? 0 : 1]);
}
}
return result;
}
}
// Accepted solution for LeetCode #2851: String Transformation
package main
// https://space.bilibili.com/206214
const mod = 1_000_000_007
type matrix [][]int
func newMatrix(n, m int) matrix {
a := make(matrix, n)
for i := range a {
a[i] = make([]int, m)
}
return a
}
func newIdentityMatrix(n int) matrix {
a := make(matrix, n)
for i := range a {
a[i] = make([]int, n)
a[i][i] = 1
}
return a
}
func (a matrix) mul(b matrix) matrix {
c := newMatrix(len(a), len(b[0]))
for i, row := range a {
for j := range b[0] {
for k, v := range row {
c[i][j] = (c[i][j] + v*b[k][j]) % mod
}
}
}
return c
}
func (a matrix) pow(n int64) matrix {
res := newIdentityMatrix(len(a))
for ; n > 0; n /= 2 {
if n%2 > 0 {
res = res.mul(a)
}
a = a.mul(a)
}
return res
}
func numberOfWays(s, t string, k int64) int {
n := len(s)
calcMaxMatchLengths := func(s string) []int {
match := make([]int, len(s))
for i, c := 1, 0; i < len(s); i++ {
v := s[i]
for c > 0 && s[c] != v {
c = match[c-1]
}
if s[c] == v {
c++
}
match[i] = c
}
return match
}
kmpSearch := func(text, pattern string) (cnt int) {
match := calcMaxMatchLengths(pattern)
lenP := len(pattern)
c := 0
for _, v := range text {
for c > 0 && pattern[c] != byte(v) {
c = match[c-1]
}
if pattern[c] == byte(v) {
c++
}
if c == lenP {
cnt++
c = match[c-1]
}
}
return
}
c := kmpSearch(s+s[:n-1], t)
m := matrix{
{c - 1, c},
{n - c, n - 1 - c},
}.pow(k)
if s == t {
return m[0][0]
}
return m[0][1]
}
# Accepted solution for LeetCode #2851: String Transformation
"""
DP, Z-algorithm, Fast mod.
Approach
How to represent a string?
Each operation is just a rotation. Each result string can be represented by an integer from 0 to n - 1. Namely, it's just the new index of s[0].
How to find the integer(s) that can represent string t?
Create a new string s + t + t (length = 3 * n).
Use Z-algorithm (or KMP), for each n <= index < 2 * n, calculate the maximum prefix length that each substring starts from index can match, if the length >= n, then (index - n) is a valid integer representation.
How to get the result?
It's a very obvious DP.
If we use an integer to represent a string, we only need to consider the transition from zero to non-zero and from non-zero to zero. In other words, all the non-zero strings should have the same result.
So let dp[t][i = 0/1] be the number of ways to get the zero/nonzero string
after excatly t steps.
Then
dp[t][0] = dp[t - 1][1] * (n - 1).
All the non zero strings can make it.
dp[t][1] = dp[t - 1][0] + dp[t - 1] * (n - 2).
For a particular non zero string, all the other non zero strings and zero string can make it.
We have dp[0][0] = 1 and dp[0][1] = 0
Use matrix multiplication.
How to calculate dp[k][x = 0, 1] faster?
Use matrix multiplication
vector (dp[t - 1][0], dp[t - 1][1])
multiplies matrix
[0 1]
[n - 1 n - 2]
== vector (dp[t][0], dp[t - 1][1]).
So we just need to calculate the kth power of the matrix which can be done by fast power algorith.
Complexity
Time complexity:
O(n + logk)
Space complexity:
O(n)
"""
class Solution:
M: int = 1000000007
def add(self, x: int, y: int) -> int:
x += y
if x >= self.M:
x -= self.M
return x
def mul(self, x: int, y: int) -> int:
return int(x * y % self.M)
def getZ(self, s: str) -> List[int]:
n = len(s)
z = [0] * n
left = right = 0
for i in range(1, n):
if i <= right and z[i - left] <= right - i:
z[i] = z[i - left]
else:
z_i = max(0, right - i + 1)
while i + z_i < n and s[i + z_i] == s[z_i]:
z_i += 1
z[i] = z_i
if i + z[i] - 1 > right:
left = i
right = i + z[i] - 1
return z
def matrixMultiply(self, a: List[List[int]], b: List[List[int]]) -> List[List[int]]:
m = len(a)
n = len(a[0])
p = len(b[0])
r = [[0] * p for _ in range(m)]
for i in range(m):
for j in range(p):
for k in range(n):
r[i][j] = self.add(r[i][j], self.mul(a[i][k], b[k][j]))
return r
def matrixPower(self, a: List[List[int]], y: int) -> List[List[int]]:
n = len(a)
r = [[0] * n for _ in range(n)]
for i in range(n):
r[i][i] = 1
x = [a[i][:] for i in range(n)]
while y > 0:
if y & 1:
r = self.matrixMultiply(r, x)
x = self.matrixMultiply(x, x)
y >>= 1
return r
def numberOfWays(self, s: str, t: str, k: int) -> int:
n = len(s)
dp = self.matrixPower([[0, 1], [n - 1, n - 2]], k)[0]
s += t + t
z = self.getZ(s)
m = n + n
result = 0
for i in range(n, m):
if z[i] >= n:
result = self.add(result, dp[0] if i - n == 0 else dp[1])
return result
// Accepted solution for LeetCode #2851: String Transformation
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #2851: String Transformation
// class Solution {
// private static final int M = 1000000007;
//
// private int add(int x, int y) {
// if ((x += y) >= M) {
// x -= M;
// }
// return x;
// }
//
// private int mul(long x, long y) {
// return (int) (x * y % M);
// }
//
// private int[] getZ(String s) {
// int n = s.length();
// int[] z = new int[n];
// for (int i = 1, left = 0, right = 0; i < n; ++i) {
// if (i <= right && z[i - left] <= right - i) {
// z[i] = z[i - left];
// } else {
// int z_i = Math.max(0, right - i + 1);
// while (i + z_i < n && s.charAt(i + z_i) == s.charAt(z_i)) {
// z_i++;
// }
// z[i] = z_i;
// }
// if (i + z[i] - 1 > right) {
// left = i;
// right = i + z[i] - 1;
// }
// }
// return z;
// }
//
// private int[][] matrixMultiply(int[][] a, int[][] b) {
// int m = a.length, n = a[0].length, p = b[0].length;
// int[][] r = new int[m][p];
// for (int i = 0; i < m; ++i) {
// for (int j = 0; j < p; ++j) {
// for (int k = 0; k < n; ++k) {
// r[i][j] = add(r[i][j], mul(a[i][k], b[k][j]));
// }
// }
// }
// return r;
// }
//
// private int[][] matrixPower(int[][] a, long y) {
// int n = a.length;
// int[][] r = new int[n][n];
// for (int i = 0; i < n; ++i) {
// r[i][i] = 1;
// }
// int[][] x = new int[n][n];
// for (int i = 0; i < n; ++i) {
// System.arraycopy(a[i], 0, x[i], 0, n);
// }
// while (y > 0) {
// if ((y & 1) == 1) {
// r = matrixMultiply(r, x);
// }
// x = matrixMultiply(x, x);
// y >>= 1;
// }
// return r;
// }
//
// public int numberOfWays(String s, String t, long k) {
// int n = s.length();
// int[] dp = matrixPower(new int[][] {{0, 1}, {n - 1, n - 2}}, k)[0];
// s += t + t;
// int[] z = getZ(s);
// int m = n + n;
// int result = 0;
// for (int i = n; i < m; ++i) {
// if (z[i] >= n) {
// result = add(result, dp[i - n == 0 ? 0 : 1]);
// }
// }
// return result;
// }
// }
// Accepted solution for LeetCode #2851: String Transformation
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #2851: String Transformation
// class Solution {
// private static final int M = 1000000007;
//
// private int add(int x, int y) {
// if ((x += y) >= M) {
// x -= M;
// }
// return x;
// }
//
// private int mul(long x, long y) {
// return (int) (x * y % M);
// }
//
// private int[] getZ(String s) {
// int n = s.length();
// int[] z = new int[n];
// for (int i = 1, left = 0, right = 0; i < n; ++i) {
// if (i <= right && z[i - left] <= right - i) {
// z[i] = z[i - left];
// } else {
// int z_i = Math.max(0, right - i + 1);
// while (i + z_i < n && s.charAt(i + z_i) == s.charAt(z_i)) {
// z_i++;
// }
// z[i] = z_i;
// }
// if (i + z[i] - 1 > right) {
// left = i;
// right = i + z[i] - 1;
// }
// }
// return z;
// }
//
// private int[][] matrixMultiply(int[][] a, int[][] b) {
// int m = a.length, n = a[0].length, p = b[0].length;
// int[][] r = new int[m][p];
// for (int i = 0; i < m; ++i) {
// for (int j = 0; j < p; ++j) {
// for (int k = 0; k < n; ++k) {
// r[i][j] = add(r[i][j], mul(a[i][k], b[k][j]));
// }
// }
// }
// return r;
// }
//
// private int[][] matrixPower(int[][] a, long y) {
// int n = a.length;
// int[][] r = new int[n][n];
// for (int i = 0; i < n; ++i) {
// r[i][i] = 1;
// }
// int[][] x = new int[n][n];
// for (int i = 0; i < n; ++i) {
// System.arraycopy(a[i], 0, x[i], 0, n);
// }
// while (y > 0) {
// if ((y & 1) == 1) {
// r = matrixMultiply(r, x);
// }
// x = matrixMultiply(x, x);
// y >>= 1;
// }
// return r;
// }
//
// public int numberOfWays(String s, String t, long k) {
// int n = s.length();
// int[] dp = matrixPower(new int[][] {{0, 1}, {n - 1, n - 2}}, k)[0];
// s += t + t;
// int[] z = getZ(s);
// int m = n + n;
// int result = 0;
// for (int i = n; i < m; ++i) {
// if (z[i] >= n) {
// result = add(result, dp[i - n == 0 ? 0 : 1]);
// }
// }
// return result;
// }
// }
Use this to step through a reusable interview workflow for this problem.
Pure recursion explores every possible choice at each step. With two choices per state (take or skip), the decision tree has 2ⁿ leaves. The recursion stack uses O(n) space. Many subproblems are recomputed exponentially many times.
Each cell in the DP table is computed exactly once from previously solved subproblems. The table dimensions determine both time and space. Look for the state variables — each unique combination of state values is one cell. Often a rolling array can reduce space by one dimension.
Review these before coding to avoid predictable interview regressions.
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.
Wrong move: An incomplete state merges distinct subproblems and caches incorrect answers.
Usually fails on: Correctness breaks on cases that differ only in hidden state.
Fix: Define state so each unique subproblem maps to one DP cell.