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.
Build confidence with an intuition-first walkthrough focused on array fundamentals.
You are given a 0-indexed array words consisting of distinct strings.
The string words[i] can be paired with the string words[j] if:
words[i] is equal to the reversed string of words[j].0 <= i < j < words.length.Return the maximum number of pairs that can be formed from the array words.
Note that each string can belong in at most one pair.
Example 1:
Input: words = ["cd","ac","dc","ca","zz"] Output: 2 Explanation: In this example, we can form 2 pair of strings in the following way: - We pair the 0th string with the 2nd string, as the reversed string of word[0] is "dc" and is equal to words[2]. - We pair the 1st string with the 3rd string, as the reversed string of word[1] is "ca" and is equal to words[3]. It can be proven that 2 is the maximum number of pairs that can be formed.
Example 2:
Input: words = ["ab","ba","cc"] Output: 1 Explanation: In this example, we can form 1 pair of strings in the following way: - We pair the 0th string with the 1st string, as the reversed string of words[1] is "ab" and is equal to words[0]. It can be proven that 1 is the maximum number of pairs that can be formed.
Example 3:
Input: words = ["aa","ab"] Output: 0 Explanation: In this example, we are unable to form any pair of strings.
Constraints:
1 <= words.length <= 50words[i].length == 2words consists of distinct strings.words[i] contains only lowercase English letters.Problem summary: You are given a 0-indexed array words consisting of distinct strings. The string words[i] can be paired with the string words[j] if: The string words[i] is equal to the reversed string of words[j]. 0 <= i < j < words.length. Return the maximum number of pairs that can be formed from the array words. Note that each string can belong in at most one pair.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map
["cd","ac","dc","ca","zz"]
["ab","ba","cc"]
["aa","ab"]
group-shifted-strings)palindrome-pairs)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2744: Find Maximum Number of String Pairs
class Solution {
public int maximumNumberOfStringPairs(String[] words) {
Map<Integer, Integer> cnt = new HashMap<>();
int ans = 0;
for (var w : words) {
int a = w.charAt(0) - 'a', b = w.charAt(1) - 'a';
ans += cnt.getOrDefault(b << 5 | a, 0);
cnt.merge(a << 5 | b, 1, Integer::sum);
}
return ans;
}
}
// Accepted solution for LeetCode #2744: Find Maximum Number of String Pairs
func maximumNumberOfStringPairs(words []string) (ans int) {
cnt := map[int]int{}
for _, w := range words {
a, b := int(w[0]-'a'), int(w[1]-'a')
ans += cnt[b<<5|a]
cnt[a<<5|b]++
}
return
}
# Accepted solution for LeetCode #2744: Find Maximum Number of String Pairs
class Solution:
def maximumNumberOfStringPairs(self, words: List[str]) -> int:
cnt = Counter()
ans = 0
for w in words:
ans += cnt[w[::-1]]
cnt[w] += 1
return ans
// Accepted solution for LeetCode #2744: Find Maximum Number of String Pairs
pub fn maximum_number_of_string_pairs(words: Vec<String>) -> i32 {
let tables = words
.into_iter()
.map(|s| {
s.bytes().fold(vec![0; 26], |mut acc, b| {
let index = (b - b'a') as usize;
acc[index] += 1;
acc
})
})
.collect::<Vec<Vec<i32>>>();
let mut ret = 0;
for i in 0..tables.len() {
for j in (i + 1)..tables.len() {
if tables[i] == tables[j] {
ret += 1;
}
}
}
ret
}
fn main() {
let words = vec![
"cd".to_string(),
"ac".to_string(),
"dc".to_string(),
"ca".to_string(),
"zz".to_string(),
];
let ret = maximum_number_of_string_pairs(words);
println!("ret={ret}");
}
#[test]
fn test_maximum_number_of_string_pairs() {
{
let words = vec![
"cd".to_string(),
"ac".to_string(),
"dc".to_string(),
"ca".to_string(),
"zz".to_string(),
];
let ret = maximum_number_of_string_pairs(words);
assert_eq!(ret, 2);
}
{
let words = vec![
"ab".to_string(),
"ba".to_string(),
"cc".to_string(),
"ca".to_string(),
"zz".to_string(),
];
let ret = maximum_number_of_string_pairs(words);
assert_eq!(ret, 1);
}
{
let words = vec!["aa".to_string(), "ab".to_string()];
let ret = maximum_number_of_string_pairs(words);
assert_eq!(ret, 0);
}
}
// Accepted solution for LeetCode #2744: Find Maximum Number of String Pairs
function maximumNumberOfStringPairs(words: string[]): number {
const cnt: { [key: number]: number } = {};
let ans = 0;
for (const w of words) {
const [a, b] = [w.charCodeAt(0) - 97, w.charCodeAt(w.length - 1) - 97];
ans += cnt[(b << 5) | a] || 0;
cnt[(a << 5) | b] = (cnt[(a << 5) | b] || 0) + 1;
}
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.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.