Strings Differ by One Character
Problem
Given a list of strings dict where all the strings are of the same length.
Return true if there are 2 strings that only differ by 1 character in the same index, otherwise return false.
Examples
Example 1:
Input: dict = ["abcd","acbd", "aacd"]
Output: true
Explanation: Strings "a**b** cd" and "a**a** cd" differ only by one character in the index 1.
Example 2:
Input: dict = ["ab","cd","yz"]
Output: false
Example 3:
Input: dict = ["abcd","cccc","abyd","abab"]
Output: true
Constraints:
- The number of characters in
dict <= 10^5 dict[i].length == dict[j].lengthdict[i]should be unique.dict[i]contains only lowercase English letters.
Follow up: Could you solve this problem in O(n * m) where n is the
length of dict and m is the length of each string.
Solution
Method 1 - Hashing with Wildcards
Intuition
If two strings differ by exactly one character at the same index, then if we replace that character with a wildcard (e.g., '*'), the resulting string will be the same for both. We can use a hash set to check for such collisions efficiently.
Approach
For each string, for each index, replace the character at that index with a wildcard and check if this new string has been seen before. If yes, return true. Otherwise, add it to the set. If no such pair is found, return false.
Code
C++
#include <vector>
#include <string>
#include <unordered_set>
using namespace std;
class Solution {
public:
bool differByOne(vector<string>& dict) {
unordered_set<string> seen;
int m = dict[0].size();
for (const string& word : dict) {
for (int i = 0; i < m; ++i) {
string t = word;
t[i] = '*';
if (seen.count(t)) return true;
seen.insert(t);
}
}
return false;
}
};
Go
func differByOne(dict []string) bool {
seen := make(map[string]struct{})
m := len(dict[0])
for _, word := range dict {
for i := 0; i < m; i++ {
t := word[:i] + "*" + word[i+1:]
if _, ok := seen[t]; ok {
return true
}
seen[t] = struct{}{}
}
}
return false
}
Java
import java.util.*;
class Solution {
public boolean differByOne(String[] dict) {
Set<String> seen = new HashSet<>();
int m = dict[0].length();
for (String word : dict) {
for (int i = 0; i < m; i++) {
String t = word.substring(0, i) + "*" + word.substring(i+1);
if (seen.contains(t)) return true;
seen.add(t);
}
}
return false;
}
}
Kotlin
fun differByOne(dict: Array<String>): Boolean {
val seen = mutableSetOf<String>()
val m = dict[0].length
for (word in dict) {
for (i in 0 until m) {
val t = word.substring(0, i) + "*" + word.substring(i+1)
if (t in seen) return true
seen.add(t)
}
}
return false
}
Python
def differByOne(dict: list[str]) -> bool:
seen = set()
m = len(dict[0])
for word in dict:
for i in range(m):
t = word[:i] + '*' + word[i+1:]
if t in seen:
return True
seen.add(t)
return False
Rust
use std::collections::HashSet;
pub fn differ_by_one(dict: Vec<String>) -> bool {
let m = dict[0].len();
let mut seen = HashSet::new();
for word in &dict {
let bytes = word.as_bytes();
for i in 0..m {
let mut t = bytes.to_vec();
t[i] = b'*';
if seen.contains(&t) {
return true;
}
seen.insert(t);
}
}
false
}
TypeScript
function differByOne(dict: string[]): boolean {
const seen = new Set<string>();
const m = dict[0].length;
for (const word of dict) {
for (let i = 0; i < m; i++) {
const t = word.slice(0, i) + '*' + word.slice(i + 1);
if (seen.has(t)) return true;
seen.add(t);
}
}
return false;
}
Complexity
- ⏰ Time complexity:
O(n * m)where n is the number of strings and m is the length of each string. - 🧺 Space complexity:
O(n * m)for storing the wildcarded strings.