Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You are given two strings s and t of the same length, and two integer arrays nextCost and previousCost.
In one operation, you can pick any index i of s, and perform either one of the following actions:
s[i] to the next letter in the alphabet. If s[i] == 'z', you should replace it with 'a'. This operation costs nextCost[j] where j is the index of s[i] in the alphabet.s[i] to the previous letter in the alphabet. If s[i] == 'a', you should replace it with 'z'. This operation costs previousCost[j] where j is the index of s[i] in the alphabet.The shift distance is the minimum total cost of operations required to transform s into t.
Return the shift distance from s to t.
Example 1:
Input: s = "abab", t = "baba", nextCost = [100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], previousCost = [1,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
Output: 2
Explanation:
i = 0 and shift s[0] 25 times to the previous character for a total cost of 1.i = 1 and shift s[1] 25 times to the next character for a total cost of 0.i = 2 and shift s[2] 25 times to the previous character for a total cost of 1.i = 3 and shift s[3] 25 times to the next character for a total cost of 0.Example 2:
Input: s = "leet", t = "code", nextCost = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], previousCost = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
Output: 31
Explanation:
i = 0 and shift s[0] 9 times to the previous character for a total cost of 9.i = 1 and shift s[1] 10 times to the next character for a total cost of 10.i = 2 and shift s[2] 1 time to the previous character for a total cost of 1.i = 3 and shift s[3] 11 times to the next character for a total cost of 11.Constraints:
1 <= s.length == t.length <= 105s and t consist only of lowercase English letters.nextCost.length == previousCost.length == 260 <= nextCost[i], previousCost[i] <= 109Problem summary: You are given two strings s and t of the same length, and two integer arrays nextCost and previousCost. In one operation, you can pick any index i of s, and perform either one of the following actions: Shift s[i] to the next letter in the alphabet. If s[i] == 'z', you should replace it with 'a'. This operation costs nextCost[j] where j is the index of s[i] in the alphabet. Shift s[i] to the previous letter in the alphabet. If s[i] == 'a', you should replace it with 'z'. This operation costs previousCost[j] where j is the index of s[i] in the alphabet. The shift distance is the minimum total cost of operations required to transform s into t. Return the shift distance from s to t.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array
"abab" "baba" [100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] [1,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
"leet" "code" [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
shifting-letters)shifting-letters-ii)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3361: Shift Distance Between Two Strings
class Solution {
public long shiftDistance(String s, String t, int[] nextCost, int[] previousCost) {
int m = 26;
long[] s1 = new long[(m << 1) + 1];
long[] s2 = new long[(m << 1) + 1];
for (int i = 0; i < (m << 1); i++) {
s1[i + 1] = s1[i] + nextCost[i % m];
s2[i + 1] = s2[i] + previousCost[(i + 1) % m];
}
long ans = 0;
for (int i = 0; i < s.length(); i++) {
int x = s.charAt(i) - 'a';
int y = t.charAt(i) - 'a';
long c1 = s1[y + (y < x ? m : 0)] - s1[x];
long c2 = s2[x + (x < y ? m : 0)] - s2[y];
ans += Math.min(c1, c2);
}
return ans;
}
}
// Accepted solution for LeetCode #3361: Shift Distance Between Two Strings
func shiftDistance(s string, t string, nextCost []int, previousCost []int) (ans int64) {
m := 26
s1 := make([]int64, (m<<1)+1)
s2 := make([]int64, (m<<1)+1)
for i := 0; i < (m << 1); i++ {
s1[i+1] = s1[i] + int64(nextCost[i%m])
s2[i+1] = s2[i] + int64(previousCost[(i+1)%m])
}
for i := 0; i < len(s); i++ {
x := int(s[i] - 'a')
y := int(t[i] - 'a')
z := y
if y < x {
z += m
}
c1 := s1[z] - s1[x]
z = x
if x < y {
z += m
}
c2 := s2[z] - s2[y]
ans += min(c1, c2)
}
return
}
# Accepted solution for LeetCode #3361: Shift Distance Between Two Strings
class Solution:
def shiftDistance(
self, s: str, t: str, nextCost: List[int], previousCost: List[int]
) -> int:
m = 26
s1 = [0] * (m << 1 | 1)
s2 = [0] * (m << 1 | 1)
for i in range(m << 1):
s1[i + 1] = s1[i] + nextCost[i % m]
s2[i + 1] = s2[i] + previousCost[(i + 1) % m]
ans = 0
for a, b in zip(s, t):
x, y = ord(a) - ord("a"), ord(b) - ord("a")
c1 = s1[y + m if y < x else y] - s1[x]
c2 = s2[x + m if x < y else x] - s2[y]
ans += min(c1, c2)
return ans
// Accepted solution for LeetCode #3361: Shift Distance Between Two Strings
// 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 #3361: Shift Distance Between Two Strings
// class Solution {
// public long shiftDistance(String s, String t, int[] nextCost, int[] previousCost) {
// int m = 26;
// long[] s1 = new long[(m << 1) + 1];
// long[] s2 = new long[(m << 1) + 1];
// for (int i = 0; i < (m << 1); i++) {
// s1[i + 1] = s1[i] + nextCost[i % m];
// s2[i + 1] = s2[i] + previousCost[(i + 1) % m];
// }
// long ans = 0;
// for (int i = 0; i < s.length(); i++) {
// int x = s.charAt(i) - 'a';
// int y = t.charAt(i) - 'a';
// long c1 = s1[y + (y < x ? m : 0)] - s1[x];
// long c2 = s2[x + (x < y ? m : 0)] - s2[y];
// ans += Math.min(c1, c2);
// }
// return ans;
// }
// }
// Accepted solution for LeetCode #3361: Shift Distance Between Two Strings
function shiftDistance(s: string, t: string, nextCost: number[], previousCost: number[]): number {
const m = 26;
const s1: number[] = Array((m << 1) + 1).fill(0);
const s2: number[] = Array((m << 1) + 1).fill(0);
for (let i = 0; i < m << 1; i++) {
s1[i + 1] = s1[i] + nextCost[i % m];
s2[i + 1] = s2[i] + previousCost[(i + 1) % m];
}
let ans = 0;
const a = 'a'.charCodeAt(0);
for (let i = 0; i < s.length; i++) {
const x = s.charCodeAt(i) - a;
const y = t.charCodeAt(i) - a;
const c1 = s1[y + (y < x ? m : 0)] - s1[x];
const c2 = s2[x + (x < y ? m : 0)] - s2[y];
ans += Math.min(c1, c2);
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.