Can Convert String in K Moves — Medium Problem & Solution
You have k moves, numbered 1 through k. On move i you may pick an index of s not chosen before and shift its character forward by i positions in the…
- Difficulty: Medium
- Topics: Strings, Hash Table, Greedy
- Asked at: Amazon, Google, Adobe
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
You have k moves, numbered 1 through k. On move i you may pick an index of s not chosen before and shift its character forward by i positions in the alphabet, wrapping z around to a. You may also skip a move.
Return true if s can be turned into t within those k moves.
Example 1
Input: s = "input", t = "ouput", k = 9
Output: true
Explanation: Shift index 0 by 6 on move 6 and index 4 by 1 on move 1.
Example 2
Input: s = "abc", t = "bcd", k = 10
Output: false
Explanation: All three need a shift of 1, but only moves 1 and 27 provide that — and 27 is beyond k.
Example 3
Input: s = "aab", t = "bbb", k = 27
Output: true
Explanation: The two shifts of 1 use moves 1 and 27.
Constraints
1 <= s.length, t.length <= 1000000 <= k <= 1000000s and t consist of lowercase English letters.
How to solve Can Convert String in K Moves
The required shift per index is forced, and the move numbers that produce a given shift form an arithmetic progression with step 26. Counting how many indices already claimed each shift tells you exactly which move number the next one needs.
Approach
- If the two strings have different lengths, the answer is immediately
false. - For each index, compute
shift = (t[i] - s[i] + 26) % 26and skip it when it is 0. - Look up how many indices have already taken this shift, say
used; the move needed isshift + 26 * used. - If that move exceeds
k, returnfalse; otherwise record the claim and continue.
Why it works
Move m shifts by m mod 26, so the moves capable of shift d are exactly d, d+26, d+52, …. Assigning them in increasing order is optimal — any other assignment uses a move at least as large for some index. The check therefore fails only when no assignment exists.
Complexity
- Time —
O(n) - Space —
O(26)
Pitfalls
- Counting a shift of 0 as needing a move wastes the budget and rejects valid inputs.
- Forgetting the length check compares mismatched indices.
shift + 26 * usedoverflows 32 bits only for absurd inputs, but alongis the safe habit.
Reference solution
Python
def canConvertString(s: str, t: str, k: int) -> bool:
if len(s) != len(t):
return False
used = [0] * 26
for a, b in zip(s, t):
shift = (ord(b) - ord(a)) % 26
if shift == 0:
continue
move = shift + 26 * used[shift]
used[shift] += 1
if move > k:
return False
return TrueJavaScript
var canConvertString = function(s, t, k) {
if (s.length !== t.length) return false;
var used = [];
for (var u = 0; u < 26; u++) used.push(0);
for (var i = 0; i < s.length; i++) {
var shift = ((t.charCodeAt(i) - s.charCodeAt(i)) % 26 + 26) % 26;
if (shift === 0) continue;
var move = shift + 26 * used[shift];
used[shift]++;
if (move > k) return false;
}
return true;
};Also on the editorial tab: C, C#, C++, Go, Java, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.