Words Within Two Edits of Dictionary

medium string hamming distance brute force

Problem

You are given two string arrays queries and dictionary. Every word in both arrays has the same length n. One edit changes a single letter of a query word to any other letter. Return every query word that can be turned into some dictionary word using at most two edits, in their original order.

Because both words have equal length, the minimum number of edits between a query and a dictionary word is just the count of positions where their letters differ (the Hamming distance). A query qualifies if that count is ≤ 2 for at least one dictionary word.

Inputqueries = ["word","note","ants","wood"], dictionary = ["wood","joke","moat"]
Output["word","note","wood"]
"word"→"wood" needs 1 edit; "note"→"joke" needs 2; "wood" matches with 0; "ants" needs more than 2 against every dictionary word.

def twoEditWords(queries, dictionary):
    result = []
    for q in queries:                       # each query word, keep order
        for d in dictionary:                # try every dictionary word
            diff = 0
            for i in range(len(q)):         # count mismatched positions
                if q[i] != d[i]:
                    diff += 1
                    if diff > 2:            # early exit, can't qualify
                        break
            if diff <= 2:                   # within two edits
                result.append(q)
                break                       # one match is enough
    return result
function twoEditWords(queries, dictionary) {
  const result = [];
  for (const q of queries) {                 // each query word, keep order
    for (const d of dictionary) {            // try every dictionary word
      let diff = 0;
      for (let i = 0; i < q.length; i++) {   // count mismatched positions
        if (q[i] !== d[i]) {
          diff++;
          if (diff > 2) break;               // early exit, can't qualify
        }
      }
      if (diff <= 2) {                        // within two edits
        result.push(q);
        break;                               // one match is enough
      }
    }
  }
  return result;
}
List<String> twoEditWords(String[] queries, String[] dictionary) {
    List<String> result = new ArrayList<>();
    for (String q : queries) {                  // each query word, keep order
        for (String d : dictionary) {           // try every dictionary word
            int diff = 0;
            for (int i = 0; i < q.length(); i++) { // count mismatches
                if (q.charAt(i) != d.charAt(i)) {
                    diff++;
                    if (diff > 2) break;        // early exit
                }
            }
            if (diff <= 2) {                     // within two edits
                result.add(q);
                break;                          // one match is enough
            }
        }
    }
    return result;
}
vector<string> twoEditWords(vector<string>& queries, vector<string>& dictionary) {
    vector<string> result;
    for (auto& q : queries) {                    // each query word, keep order
        for (auto& d : dictionary) {             // try every dictionary word
            int diff = 0;
            for (int i = 0; i < (int)q.size(); i++) { // count mismatches
                if (q[i] != d[i]) {
                    diff++;
                    if (diff > 2) break;         // early exit
                }
            }
            if (diff <= 2) {                      // within two edits
                result.push_back(q);
                break;                           // one match is enough
            }
        }
    }
    return result;
}
Time: O(Q · D · n) Space: O(1) extra (output aside)