Watch 10 video solutions for Shifting Letters II, a medium level problem involving Array, String, Prefix Sum. This walkthrough by codestorywithMIK has 18,986 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
You are given a string s of lowercase English letters and a 2D integer array shifts where shifts[i] = [starti, endi, directioni]. For every i, shift the characters in s from the index starti to the index endi (inclusive) forward if directioni = 1, or shift the characters backward if directioni = 0.
Shifting a character forward means replacing it with the next letter in the alphabet (wrapping around so that 'z' becomes 'a'). Similarly, shifting a character backward means replacing it with the previous letter in the alphabet (wrapping around so that 'a' becomes 'z').
Return the final string after all such shifts to s are applied.
Example 1:
Input: s = "abc", shifts = [[0,1,0],[1,2,1],[0,2,1]] Output: "ace" Explanation: Firstly, shift the characters from index 0 to index 1 backward. Now s = "zac". Secondly, shift the characters from index 1 to index 2 forward. Now s = "zbd". Finally, shift the characters from index 0 to index 2 forward. Now s = "ace".
Example 2:
Input: s = "dztz", shifts = [[0,0,0],[1,1,1]] Output: "catz" Explanation: Firstly, shift the characters from index 0 to index 0 backward. Now s = "cztz". Finally, shift the characters from index 1 to index 1 forward. Now s = "catz".
Constraints:
1 <= s.length, shifts.length <= 5 * 104shifts[i].length == 30 <= starti <= endi < s.length0 <= directioni <= 1s consists of lowercase English letters.Problem Overview: You receive a lowercase string s and several shift operations. Each operation specifies a range [l, r] and a direction. All characters in that range shift forward or backward in the alphabet. After applying every operation, return the final string.
Approach 1: Direct Simulation (O(n * m) time, O(1) space)
The most straightforward method applies each shift operation directly to the affected substring. For every query, iterate from l to r and update each character by shifting it forward or backward using modular arithmetic ((c - 'a' ± 1) % 26). This mirrors the problem statement and is easy to implement. The drawback is performance: if the string length is n and there are m operations, each potentially touching up to n characters, the worst‑case runtime becomes O(n * m). This works for small inputs but quickly becomes too slow when both the string and the number of operations are large. It mainly helps verify correctness before optimizing.
Approach 2: Prefix Sum Array (O(n + m) time, O(n) space)
A more efficient solution treats shifts like range updates. Instead of updating every character immediately, record the effect of each operation using a difference array. For a forward shift on [l, r], add +1 at index l and -1 at r + 1. For a backward shift, apply -1 and +1. After processing all operations, compute a running prefix sum to determine the total shift affecting each position. Then apply the final shift to each character using modulo 26. This converts repeated range updates into constant‑time operations and processes the string only once. The technique is a classic use of a prefix sum difference array and works especially well for problems involving many range modifications.
During the final pass, convert each character to its numeric position, apply the accumulated shift (handling negative values with modulo), and map it back to a letter. The algorithm touches each query once and each character once, giving O(n + m) time complexity and O(n) extra space.
Recommended for interviews: The prefix sum approach is what interviewers expect. It demonstrates recognition of range‑update patterns and efficient use of arrays. The brute-force simulation shows you understand the problem mechanics, but the optimized solution proves you can reduce repeated work using prefix accumulation techniques often seen in string and array manipulation problems.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Direct Simulation | O(n * m) | O(1) | Small inputs or quick baseline implementation to verify correctness |
| Prefix Sum Array (Difference Array) | O(n + m) | O(n) | Large number of range updates where applying shifts individually would be too slow |