|
| 1 | +Here is the `README.md` in LeetCode-style markdown for **1657. Determine if Two Strings Are Close**: |
| 2 | + |
| 3 | +--- |
| 4 | + |
| 5 | +# 1657. Determine if Two Strings Are Close |
| 6 | + |
| 7 | +> Difficulty: Medium |
| 8 | +> Tags: Hash Table, String, Counting, Sorting |
| 9 | +> Source: Weekly Contest 215 Q2 |
| 10 | +
|
| 11 | +## Problem |
| 12 | + |
| 13 | +Two strings are considered **close** if you can attain one from the other using the following operations: |
| 14 | + |
| 15 | +1. **Swap any two existing characters.** |
| 16 | + - For example, `a<u>b</u>cd<u>e</u> → a<u>e</u>cd<u>b</u>` |
| 17 | + |
| 18 | +2. **Transform every occurrence of one existing character into another existing character, and do the same with the other character.** |
| 19 | + - For example, `<u>aa</u>c<u>abb</u> → <u>bb</u>c<u>baa</u>` (all `a`'s turn into `b`'s, and all `b`'s turn into `a`'s) |
| 20 | + |
| 21 | +You can use the operations on either string as many times as necessary. |
| 22 | + |
| 23 | +Given two strings, `word1` and `word2`, return `true` if `word1` and `word2` are **close**, and `false` otherwise. |
| 24 | + |
| 25 | +### Example 1: |
| 26 | + |
| 27 | +``` |
| 28 | +Input: word1 = "abc", word2 = "bca" |
| 29 | +Output: true |
| 30 | +Explanation: You can attain word2 from word1 in 2 operations. |
| 31 | +Apply Operation 1: "a<u>bc</u>" → "a<u>cb</u>" |
| 32 | +Apply Operation 1: "<u>a</u>c<u>b</u>" → "<u>b</u>c<u>a</u>" |
| 33 | +``` |
| 34 | + |
| 35 | +### Example 2: |
| 36 | + |
| 37 | +``` |
| 38 | +Input: word1 = "a", word2 = "aa" |
| 39 | +Output: false |
| 40 | +Explanation: It is impossible to attain word2 from word1, or vice versa, in any number of operations. |
| 41 | +``` |
| 42 | + |
| 43 | +### Example 3: |
| 44 | + |
| 45 | +``` |
| 46 | +Input: word1 = "cabbba", word2 = "abbccc" |
| 47 | +Output: true |
| 48 | +Explanation: You can attain word2 from word1 in 3 operations. |
| 49 | +Apply Operation 1: "ca<u>b</u>bb<u>a</u>" → "ca<u>a</u>bb<u>b</u>" |
| 50 | +Apply Operation 2: "<u>c</u>aa<u>bbb</u>" → "<u>b</u>aa<u>ccc</u>" |
| 51 | +Apply Operation 2: "<u>baa</u>ccc" → "<u>abb</u>ccc" |
| 52 | +``` |
| 53 | + |
| 54 | +## Constraints |
| 55 | + |
| 56 | +- `1 <= word1.length, word2.length <= 10^5` |
| 57 | +- `word1` and `word2` contain only lowercase English letters. |
| 58 | + |
| 59 | +--- |
| 60 | + |
| 61 | +## Approach |
| 62 | + |
| 63 | +To determine if two strings are **close**, we need to check two main conditions: |
| 64 | +1. Both strings must contain the same types of characters. |
| 65 | +2. The frequency of characters in both strings must be the same after sorting the counts. |
| 66 | + |
| 67 | +- **Time Complexity:** $O(m + n + C \times \log C)$, where `m` and `n` are the lengths of `word1` and `word2`, respectively, and `C` is the number of letter types (26 in this case). |
| 68 | +- **Space Complexity:** $O(C)$, where `C` is the number of unique characters (26). |
| 69 | + |
| 70 | +--- |
| 71 | + |
| 72 | +## Solutions |
| 73 | + |
| 74 | +### Python |
| 75 | + |
| 76 | +```python |
| 77 | +from collections import Counter |
| 78 | + |
| 79 | +class Solution: |
| 80 | + def closeStrings(self, word1: str, word2: str) -> bool: |
| 81 | + cnt1, cnt2 = Counter(word1), Counter(word2) |
| 82 | + return sorted(cnt1.values()) == sorted(cnt2.values()) and set( |
| 83 | + cnt1.keys() |
| 84 | + ) == set(cnt2.keys()) |
| 85 | +``` |
| 86 | + |
| 87 | +### Java |
| 88 | + |
| 89 | +```java |
| 90 | +import java.util.*; |
| 91 | + |
| 92 | +class Solution { |
| 93 | + public boolean closeStrings(String word1, String word2) { |
| 94 | + int[] cnt1 = new int[26]; |
| 95 | + int[] cnt2 = new int[26]; |
| 96 | + for (int i = 0; i < word1.length(); ++i) { |
| 97 | + ++cnt1[word1.charAt(i) - 'a']; |
| 98 | + } |
| 99 | + for (int i = 0; i < word2.length(); ++i) { |
| 100 | + ++cnt2[word2.charAt(i) - 'a']; |
| 101 | + } |
| 102 | + for (int i = 0; i < 26; ++i) { |
| 103 | + if ((cnt1[i] == 0) != (cnt2[i] == 0)) { |
| 104 | + return false; |
| 105 | + } |
| 106 | + } |
| 107 | + Arrays.sort(cnt1); |
| 108 | + Arrays.sort(cnt2); |
| 109 | + return Arrays.equals(cnt1, cnt2); |
| 110 | + } |
| 111 | +} |
| 112 | +``` |
| 113 | + |
| 114 | +### C++ |
| 115 | + |
| 116 | +```cpp |
| 117 | +#include <unordered_map> |
| 118 | +#include <unordered_set> |
| 119 | +#include <vector> |
| 120 | +#include <algorithm> |
| 121 | +using namespace std; |
| 122 | + |
| 123 | +class Solution { |
| 124 | +public: |
| 125 | + bool closeStrings(string word1, string word2) { |
| 126 | + int cnt1[26]{}; |
| 127 | + int cnt2[26]{}; |
| 128 | + for (char& c : word1) { |
| 129 | + ++cnt1[c - 'a']; |
| 130 | + } |
| 131 | + for (char& c : word2) { |
| 132 | + ++cnt2[c - 'a']; |
| 133 | + } |
| 134 | + for (int i = 0; i < 26; ++i) { |
| 135 | + if ((cnt1[i] == 0) != (cnt2[i] == 0)) { |
| 136 | + return false; |
| 137 | + } |
| 138 | + } |
| 139 | + sort(cnt1, cnt1 + 26); |
| 140 | + sort(cnt2, cnt2 + 26); |
| 141 | + return equal(cnt1, cnt1 + 26, cnt2); |
| 142 | + } |
| 143 | +}; |
| 144 | +``` |
| 145 | +
|
| 146 | +### Go |
| 147 | +
|
| 148 | +```go |
| 149 | +import "sort" |
| 150 | +
|
| 151 | +func closeStrings(word1 string, word2 string) bool { |
| 152 | + cnt1 := make([]int, 26) |
| 153 | + cnt2 := make([]int, 26) |
| 154 | + for _, c := range word1 { |
| 155 | + cnt1[c-'a']++ |
| 156 | + } |
| 157 | + for _, c := range word2 { |
| 158 | + cnt2[c-'a']++ |
| 159 | + } |
| 160 | + for i := 0; i < 26; i++ { |
| 161 | + if (cnt1[i] == 0) != (cnt2[i] == 0) { |
| 162 | + return false |
| 163 | + } |
| 164 | + } |
| 165 | + sort.Ints(cnt1) |
| 166 | + sort.Ints(cnt2) |
| 167 | + return slices.Equal(cnt1, cnt2) |
| 168 | +} |
| 169 | +``` |
| 170 | + |
| 171 | +### TypeScript |
| 172 | + |
| 173 | +```ts |
| 174 | +function closeStrings(word1: string, word2: string): boolean { |
| 175 | + const cnt1 = Array(26).fill(0); |
| 176 | + const cnt2 = Array(26).fill(0); |
| 177 | + for (const c of word1) { |
| 178 | + ++cnt1[c.charCodeAt(0) - 'a'.charCodeAt(0)]; |
| 179 | + } |
| 180 | + for (const c of word2) { |
| 181 | + ++cnt2[c.charCodeAt(0) - 'a'.charCodeAt(0)]; |
| 182 | + } |
| 183 | + for (let i = 0; i < 26; ++i) { |
| 184 | + if ((cnt1[i] === 0) !== (cnt2[i] === 0)) { |
| 185 | + return false; |
| 186 | + } |
| 187 | + } |
| 188 | + cnt1.sort((a, b) => a - b); |
| 189 | + cnt2.sort((a, b) => a - b); |
| 190 | + return cnt1.join('.') === cnt2.join('.'); |
| 191 | +} |
| 192 | +``` |
| 193 | + |
| 194 | +### Rust |
| 195 | + |
| 196 | +```rust |
| 197 | +impl Solution { |
| 198 | + pub fn close_strings(word1: String, word2: String) -> bool { |
| 199 | + let mut cnt1 = vec![0; 26]; |
| 200 | + let mut cnt2 = vec![0; 26]; |
| 201 | + for c in word1.chars() { |
| 202 | + cnt1[((c as u8) - b'a') as usize] += 1; |
| 203 | + } |
| 204 | + for c in word2.chars() { |
| 205 | + cnt2[((c as u8) - b'a') as usize] += 1; |
| 206 | + } |
| 207 | + for i in 0..26 { |
| 208 | + if (cnt1[i] == 0) != (cnt2[i] == 0) { |
| 209 | + return false; |
| 210 | + } |
| 211 | + } |
| 212 | + cnt1.sort(); |
| 213 | + cnt2.sort(); |
| 214 | + cnt1 == cnt2 |
| 215 | + } |
| 216 | +} |
| 217 | +``` |
| 218 | + |
| 219 | +--- |
| 220 | + |
| 221 | +Let me know if you'd like a `.md` file download or need help with anything else! |
0 commit comments