CMD Guide
HomeDSAHashing

medium Determine if Two Strings Are Close

Problem Statement:

Two strings are considered similar if you can make one string look like the other using the following two operations:

  1. Swap any two characters.
    • For example, abde -> aedb (e and b swapped).
  2. Replace every occurrence of one character with another, and replace the other character with the first one.
    • For example, acabbb -> bcbaaa (all a's turn into b's, and all b's turn into a's)

Given two strings, word1 and word2, return true if they can be made similar, otherwise return false.

Examples

Example 1:

Example 2:

Example 3:

Constraints:

Try it yourself

Try solving this question here:

🎯 STRICT STANDOUT: Why / worked+complexity / pattern+when-not / edge / drills — Determine if Two Strings Are Close medium

Why this concept exists (judgment layer)

Close strings: you may swap any chars and reassign frequencies among existing chars — so equality of character SETS and equality of sorted FREQUENCY MULTISETS are necessary and sufficient. Not plain anagram (anagram needs exact per-char counts).

Worked example with complexity derivation

word1=aacbbc, word2=bbcaca: both length 6; set {a,b,c}; counts (2,2,2) both → true.
cabbba / abbccc: sets {a,b,c}; counts sorted [1,2,3] both → true.
aabbcc / aabbc: lengths differ → false.
uau / ssx: sets differ → false even if freq multiset similar.

Pattern + when-NOT / named alternative

PATTERN: same alphabet support + same sorted frequency signature. WHEN NOT: need exact anagram → per-char counts equal (no sort of freqs). Edit distance / one swap only → different problem.

Edge case / failure mode

Edges: length 1; all identical chars; one char exclusive to one string; n=1e5 need O(n).

Hostile-panel drills (defend the decision)

Q1. Why sorted frequencies not raw arrays?
Model answer: Ops let you move counts between letters that exist; multiset of counts must match.

Q2. Why set equality required?
Model answer: Cannot invent a letter that never appears; swaps/reassign only among present chars.

Q3. Anagram vs close?
Model answer: Anagram ⇒ same counts per letter; close allows permuting the count values across letters.

✅ Solution Determine if Two Strings Are Close

Problem Statement:

Two strings are considered similar if you can make one string look like the other using the following two operations:

  1. Swap any two characters.
    • For example, abde -> aedb (e and b swapped).
  2. Replace every occurrence of one character with another, and replace the other character with the first one.
    • For example, acabbb -> bcbaaa (all a's turn into b's, and all b's turn into a's)

Given two strings, word1 and word2, return true if they can be made similar, otherwise return false.

Examples

Example 1:

  • Input: word1 = "aacbbc", word2 = "bbcaca"
  • Expected Output: true
  • Justification: You can swap the 'a's and 'b's in word2 to make it "aacbcb", then swap the last two characters to match word1.

Example 2:

  • Input: word1 = "xxyyzz", word2 = "zzxxyy"
  • Expected Output: true
  • Justification: Swapping characters 'x' with 'z' and then 'z' with 'y' in word2 will make it "xxyyzz", which matches word1.

Example 3:

  • Input: word1 = "aabbcc", word2 = "aabbc"
  • Expected Output: false
  • Justification: The lengths of the two strings are different, so they can't be made to look the same.

Constraints:

  • 1 <= word1.length, word2.length <= 105
  • word1 and word2 contain only lowercase English letters.

Solution

To solve this problem, the first step is to ensure that both strings have the same length. If they don't, they can't be made similar. Next, we need to check if both strings have the same set of characters. If one string has a character that the other doesn't, they can't be made to look the same. Lastly, we check the frequency of each character. Both strings must have the same frequency distribution of characters for them to be transformable into one another.

This approach is effective because it simplifies the problem into three main checks: length, character set, and frequency distribution. By ensuring these conditions, we can determine if one string can be transformed into the other using the allowed operations.

Step-by-step Algorithm:

  1. Check Lengths:

    • If the lengths of word1 and word2 are not the same, return false because they cannot be transformed into each other.
  2. Initialize Frequency Arrays and Character Sets:

    • Create two integer arrays, count1 and count2, each of size 26, to store the frequency of each character in word1 and word2 respectively.
    • Create two sets, set1 and set2, to store the unique characters present in word1 and word2 respectively.
  3. Fill Frequency Arrays and Character Sets:

    • Iterate through each character in word1, update its corresponding frequency in count1, and add the character to set1.
    • Iterate through each character in word2, update its corresponding frequency in count2, and add the character to set2.
  4. Sort Frequency Arrays:

    • Sort count1 and count2. Sorting helps to compare the character frequencies directly.
  5. Compare Frequency Arrays and Character Sets:

    • Compare the sorted frequency arrays count1 and count2. If they are not the same, return false.
    • Compare the sets set1 and set2. If they are not the same, return false.
  6. Return Result:

    • If both the sorted frequency arrays and the character sets are the same, return true.

Algorithm Walkthrough:

Let's walk through the algorithm using the example word1 = "aacbbc", word2 = "bbcaca".

  1. Check Lengths:

    • Length of word1 is 6.
    • Length of word2 is 6.
    • Both lengths are the same, so proceed to the next step.
  2. Initialize Frequency Arrays and Character Sets:

    • count1 = [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, 0]
    • count2 = [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, 0]
    • set1 = {}
    • set2 = {}
  3. Fill Frequency Arrays and Character Sets:

    • For word1:
      • 'a': count1[0] becomes 1, set1 becomes {'a'}
      • 'a': count1[0] becomes 2, set1 remains {'a'}
      • 'c': count1[2] becomes 1, set1 becomes {'a', 'c'}
      • 'b': count1[1] becomes 1, set1 becomes {'a', 'b', 'c'}
      • 'b': count1[1] becomes 2, set1 remains {'a', 'b', 'c'}
      • 'c': count1[2] becomes 2, set1 remains {'a', 'b', 'c'}
    • For word2:
      • 'b': count2[1] becomes 1, set2 becomes {'b'}
      • 'b': count2[1] becomes 2, set2 remains {'b'}
      • 'c': count2[2] becomes 1, set2 becomes {'b', 'c'}
      • 'a': count2[0] becomes 1, set2 becomes {'a', 'b', 'c'}
      • 'c': count2[2] becomes 2, set2 remains {'a', 'b', 'c'}
      • 'a': count2[0] becomes 2, set2 remains {'a', 'b', 'c'}
  4. Sort Frequency Arrays:

    • Sorted count1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2]
    • Sorted count2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2]
  5. Compare Frequency Arrays and Character Sets:

    • count1 and count2 are equal after sorting.
    • set1 and set2 are equal.
  6. Return Result:

    • Since both the sorted frequency arrays and character sets are the same, return true.

Code

java
import java.util.*;

public class Solution {

  public boolean closeStrings(String word1, String word2) {
    if (word1.length() != word2.length()) {
      return false; // The strings must be of equal length
    }

    int[] count1 = new int[26]; // Frequency of characters in word1
    int[] count2 = new int[26]; // Frequency of characters in word2
    Set<Character> set1 = new HashSet<>(); // Unique characters in word1
    Set<Character> set2 = new HashSet<>(); // Unique characters in word2

    for (char c : word1.toCharArray()) {
      count1[c - 'a']++;
      set1.add(c);
    }

    for (char c : word2.toCharArray()) {
      count2[c - 'a']++;
      set2.add(c);
    }

    Arrays.sort(count1); // Sort frequencies for comparison
    Arrays.sort(count2); // Sort frequencies for comparison

    return Arrays.equals(count1, count2) && set1.equals(set2);
  }

  public static void main(String[] args) {
    Solution sol = new Solution();

    // Example 1
    System.out.println(sol.closeStrings("aacbbc", "bbcaca")); // true

    // Example 2
    System.out.println(sol.closeStrings("xxyyzz", "zzxxyy")); // true

    // Example 3
    System.out.println(sol.closeStrings("aabbcc", "aabbc")); // false
  }
}

Complexity Analysis:

Time Complexity

The time complexity of this solution is where n is the length of the input strings. This is because we need to traverse the string. The sorting operation of count array takes constant time as its size is constant.

Space Complexity

The space complexity is because we are using fixed-size arrays (of size 26) and sets, and the extra space used does not depend on the input size.

🎯 STRICT STANDOUT: Why / worked+complexity / pattern+when-not / edge / drills — Solution Determine if Two Strings Are Close

Why this concept exists (judgment layer)

Solution: length check, count[26]+sets, sort counts, compare. Elevation derives why sort(count) is O(1) (26) so total O(n), and names the algebraic invariant.

Worked example with complexity derivation

aacbbc / bbcaca:
count1 a2 b2 c2; count2 same; sets equal; sort equal → true.
Time: two O(n) scans + O(26 log 26) sort → Θ(n).
Space: O(1) extra (fixed 26) + set ≤26.
Counter: abc / abd — sets differ after counts may both be [1,1,1,0…].

Pattern + when-NOT / named alternative

PATTERN: frequency signature + alphabet support (hash/count arrays). WHEN NOT: unicode huge alphabet → HashMap counts not int[26]. When problem forbids frequency reassignment → require count1[c]==count2[c] all c.

Edge case / failure mode

Edges: a / a true; ab / aa false (freq multiset [1,1] vs [2]); hand-run aabbcc/aabbc length fail.

Hostile-panel drills (defend the decision)

Q1. Derive complexity.
Model answer: Θ(n) count + O(1) sort 26 ints → Θ(n) time, Θ(1) aux for lowercase English.

Q2. Could you skip sets if counts match after sort?
Model answer: No: support can differ with same sorted zero-padded multiset shapes — need set/support check.

Q3. abzz vs aazz?
Model answer: sets {a,b,z} vs {a,z}; counts [1,1,2] vs [2,2] — both checks fail appropriately.

🧩 Pattern · Hashing

Recognize it: Membership / frequency / “have I seen this?” in O(1) → a hash map or set.

▶ Visualize this problem (step it, predict each fork)
⛶ Open this problem debugger in explore mode
🤖 Don't fully get this? Learn it with Claude

Stuck on Determine if Two Strings Are Close? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🪜 Hint ladder (no spoilers)

Progressively stronger hints — you still solve it.

I'm working on the problem **Determine if Two Strings Are Close** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🎨 Explain the approach visually

See the technique, not just code.

Explain the optimal approach to **Determine if Two Strings Are Close** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔍 Review my solution

Catch bugs, edge cases, sub-optimality.

I'll paste my solution to **Determine if Two Strings Are Close**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔁 Drill the pattern

Lock in recognition with look-alikes.

Give me 2 problems that use the SAME underlying pattern as **Determine if Two Strings Are Close**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes