Skip to content

Commit 1926340

Browse files
authored
feat: add solutions to lc problem: No.1657 (doocs#2037)
No.1657.Determine if Two Strings Are Close
1 parent 7321fbc commit 1926340

File tree

8 files changed

+214
-115
lines changed

8 files changed

+214
-115
lines changed

solution/1600-1699/1657.Determine if Two Strings Are Close/README.md

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575

7676
<!-- 这里可写通用的实现逻辑 -->
7777

78-
**方法一:数组或哈希表 + 排序**
78+
**方法一:计数 + 排序**
7979

8080
根据题目描述,两个字符串接近,需要同时满足以下两个条件:
8181

@@ -88,7 +88,7 @@
8888

8989
遍历结束,返回 `true`
9090

91-
时间复杂度 $O(m + n)$,空间复杂度 $O(C)$。其中 $m$ 和 $n$ 分别为字符串 `word1``word2` 的长度,而 $C$ 是字母种类。本题中 $C=26$。
91+
时间复杂度 $O(m + n + C \times \log C)$,空间复杂度 $O(C)$。其中 $m$ 和 $n$ 分别为字符串 `word1``word2` 的长度,而 $C$ 是字母种类。本题中 $C=26$。
9292

9393
<!-- tabs:start -->
9494

@@ -121,18 +121,13 @@ class Solution {
121121
++cnt2[word2.charAt(i) - 'a'];
122122
}
123123
for (int i = 0; i < 26; ++i) {
124-
if ((cnt1[i] > 0 && cnt2[i] == 0) || (cnt2[i] > 0 && cnt1[i] == 0)) {
124+
if ((cnt1[i] == 0) != (cnt2[i] == 0)) {
125125
return false;
126126
}
127127
}
128128
Arrays.sort(cnt1);
129129
Arrays.sort(cnt2);
130-
for (int i = 0; i < 26; ++i) {
131-
if (cnt1[i] != cnt2[i]) {
132-
return false;
133-
}
134-
}
135-
return true;
130+
return Arrays.equals(cnt1, cnt2);
136131
}
137132
}
138133
```
@@ -152,18 +147,13 @@ public:
152147
++cnt2[c - 'a'];
153148
}
154149
for (int i = 0; i < 26; ++i) {
155-
if ((cnt1[i] > 0 && cnt2[i] == 0) || (cnt1[i] == 0 && cnt2[i] > 0)) {
150+
if ((cnt1[i] == 0) != (cnt2[i] == 0)) {
156151
return false;
157152
}
158153
}
159154
sort(cnt1, cnt1 + 26);
160155
sort(cnt2, cnt2 + 26);
161-
for (int i = 0; i < 26; ++i) {
162-
if (cnt1[i] != cnt2[i]) {
163-
return false;
164-
}
165-
}
166-
return true;
156+
return equal(cnt1, cnt1 + 26, cnt2);
167157
}
168158
};
169159
```
@@ -180,19 +170,60 @@ func closeStrings(word1 string, word2 string) bool {
180170
for _, c := range word2 {
181171
cnt2[c-'a']++
182172
}
183-
for i, v := range cnt1 {
184-
if (v > 0 && cnt2[i] == 0) || (v == 0 && cnt2[i] > 0) {
185-
return false
186-
}
173+
if !slices.EqualFunc(cnt1, cnt2, func(v1, v2 int) bool { return (v1 == 0) == (v2 == 0) }) {
174+
return false
187175
}
188176
sort.Ints(cnt1)
189177
sort.Ints(cnt2)
190-
for i, v := range cnt1 {
191-
if v != cnt2[i] {
192-
return false
193-
}
194-
}
195-
return true
178+
return slices.Equal(cnt1, cnt2)
179+
}
180+
```
181+
182+
### **TypeScript**
183+
184+
```ts
185+
function closeStrings(word1: string, word2: string): boolean {
186+
const cnt1 = Array(26).fill(0);
187+
const cnt2 = Array(26).fill(0);
188+
for (const c of word1) {
189+
++cnt1[c.charCodeAt(0) - 'a'.charCodeAt(0)];
190+
}
191+
for (const c of word2) {
192+
++cnt2[c.charCodeAt(0) - 'a'.charCodeAt(0)];
193+
}
194+
for (let i = 0; i < 26; ++i) {
195+
if ((cnt1[i] === 0) !== (cnt2[i] === 0)) {
196+
return false;
197+
}
198+
}
199+
cnt1.sort((a, b) => a - b);
200+
cnt2.sort((a, b) => a - b);
201+
return cnt1.join('.') === cnt2.join('.');
202+
}
203+
```
204+
205+
### **Rust**
206+
207+
```rust
208+
impl Solution {
209+
pub fn close_strings(word1: String, word2: String) -> bool {
210+
let mut cnt1 = vec![0; 26];
211+
let mut cnt2 = vec![0; 26];
212+
for c in word1.chars() {
213+
cnt1[((c as u8) - b'a') as usize] += 1;
214+
}
215+
for c in word2.chars() {
216+
cnt2[((c as u8) - b'a') as usize] += 1;
217+
}
218+
for i in 0..26 {
219+
if (cnt1[i] == 0) != (cnt2[i] == 0) {
220+
return false;
221+
}
222+
}
223+
cnt1.sort();
224+
cnt2.sort();
225+
cnt1 == cnt2
226+
}
196227
}
197228
```
198229

solution/1600-1699/1657.Determine if Two Strings Are Close/README_EN.md

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ Apply Operation 2: &quot;<u>baa</u>ccc&quot; -&gt; &quot;<u>abb</u>ccc&quot;
6363

6464
## Solutions
6565

66+
**Solution 1: Counting + Sorting**
67+
68+
According to the problem description, two strings are close if they meet the following two conditions simultaneously:
69+
70+
1. The strings `word1` and `word2` must contain the same types of letters.
71+
2. The arrays obtained by sorting the counts of all characters in `word1` and `word2` must be the same.
72+
73+
Therefore, we can first use an array or hash table to count the occurrences of each letter in `word1` and `word2` respectively, and then compare whether they are the same. If they are not the same, return `false` early.
74+
75+
Otherwise, we sort the corresponding counts, and then compare whether the counts at the corresponding positions are the same. If they are not the same, return `false`.
76+
77+
At the end of the traversal, return `true`.
78+
79+
The time complexity is $O(m + n + C \times \log C)$, and the space complexity is $O(C)$. Here, $m$ and $n$ are the lengths of the strings `word1` and `word2` respectively, and $C$ is the number of letter types. In this problem, $C=26$.
80+
6681
<!-- tabs:start -->
6782

6883
### **Python3**
@@ -90,18 +105,13 @@ class Solution {
90105
++cnt2[word2.charAt(i) - 'a'];
91106
}
92107
for (int i = 0; i < 26; ++i) {
93-
if ((cnt1[i] > 0 && cnt2[i] == 0) || (cnt2[i] > 0 && cnt1[i] == 0)) {
108+
if ((cnt1[i] == 0) != (cnt2[i] == 0)) {
94109
return false;
95110
}
96111
}
97112
Arrays.sort(cnt1);
98113
Arrays.sort(cnt2);
99-
for (int i = 0; i < 26; ++i) {
100-
if (cnt1[i] != cnt2[i]) {
101-
return false;
102-
}
103-
}
104-
return true;
114+
return Arrays.equals(cnt1, cnt2);
105115
}
106116
}
107117
```
@@ -121,18 +131,13 @@ public:
121131
++cnt2[c - 'a'];
122132
}
123133
for (int i = 0; i < 26; ++i) {
124-
if ((cnt1[i] > 0 && cnt2[i] == 0) || (cnt1[i] == 0 && cnt2[i] > 0)) {
134+
if ((cnt1[i] == 0) != (cnt2[i] == 0)) {
125135
return false;
126136
}
127137
}
128138
sort(cnt1, cnt1 + 26);
129139
sort(cnt2, cnt2 + 26);
130-
for (int i = 0; i < 26; ++i) {
131-
if (cnt1[i] != cnt2[i]) {
132-
return false;
133-
}
134-
}
135-
return true;
140+
return equal(cnt1, cnt1 + 26, cnt2);
136141
}
137142
};
138143
```
@@ -149,19 +154,60 @@ func closeStrings(word1 string, word2 string) bool {
149154
for _, c := range word2 {
150155
cnt2[c-'a']++
151156
}
152-
for i, v := range cnt1 {
153-
if (v > 0 && cnt2[i] == 0) || (v == 0 && cnt2[i] > 0) {
154-
return false
155-
}
157+
if !slices.EqualFunc(cnt1, cnt2, func(v1, v2 int) bool { return (v1 == 0) == (v2 == 0) }) {
158+
return false
156159
}
157160
sort.Ints(cnt1)
158161
sort.Ints(cnt2)
159-
for i, v := range cnt1 {
160-
if v != cnt2[i] {
161-
return false
162-
}
163-
}
164-
return true
162+
return slices.Equal(cnt1, cnt2)
163+
}
164+
```
165+
166+
### **TypeScript**
167+
168+
```ts
169+
function closeStrings(word1: string, word2: string): boolean {
170+
const cnt1 = Array(26).fill(0);
171+
const cnt2 = Array(26).fill(0);
172+
for (const c of word1) {
173+
++cnt1[c.charCodeAt(0) - 'a'.charCodeAt(0)];
174+
}
175+
for (const c of word2) {
176+
++cnt2[c.charCodeAt(0) - 'a'.charCodeAt(0)];
177+
}
178+
for (let i = 0; i < 26; ++i) {
179+
if ((cnt1[i] === 0) !== (cnt2[i] === 0)) {
180+
return false;
181+
}
182+
}
183+
cnt1.sort((a, b) => a - b);
184+
cnt2.sort((a, b) => a - b);
185+
return cnt1.join('.') === cnt2.join('.');
186+
}
187+
```
188+
189+
### **Rust**
190+
191+
```rust
192+
impl Solution {
193+
pub fn close_strings(word1: String, word2: String) -> bool {
194+
let mut cnt1 = vec![0; 26];
195+
let mut cnt2 = vec![0; 26];
196+
for c in word1.chars() {
197+
cnt1[((c as u8) - b'a') as usize] += 1;
198+
}
199+
for c in word2.chars() {
200+
cnt2[((c as u8) - b'a') as usize] += 1;
201+
}
202+
for i in 0..26 {
203+
if (cnt1[i] == 0) != (cnt2[i] == 0) {
204+
return false;
205+
}
206+
}
207+
cnt1.sort();
208+
cnt2.sort();
209+
cnt1 == cnt2
210+
}
165211
}
166212
```
167213

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,21 @@
1-
class Solution {
2-
public:
3-
bool closeStrings(string word1, string word2) {
4-
int cnt1[26]{};
5-
int cnt2[26]{};
6-
for (char& c : word1) {
7-
++cnt1[c - 'a'];
8-
}
9-
for (char& c : word2) {
10-
++cnt2[c - 'a'];
11-
}
12-
for (int i = 0; i < 26; ++i) {
13-
if ((cnt1[i] > 0 && cnt2[i] == 0) || (cnt1[i] == 0 && cnt2[i] > 0)) {
14-
return false;
15-
}
16-
}
17-
sort(cnt1, cnt1 + 26);
18-
sort(cnt2, cnt2 + 26);
19-
for (int i = 0; i < 26; ++i) {
20-
if (cnt1[i] != cnt2[i]) {
21-
return false;
22-
}
23-
}
24-
return true;
25-
}
1+
class Solution {
2+
public:
3+
bool closeStrings(string word1, string word2) {
4+
int cnt1[26]{};
5+
int cnt2[26]{};
6+
for (char& c : word1) {
7+
++cnt1[c - 'a'];
8+
}
9+
for (char& c : word2) {
10+
++cnt2[c - 'a'];
11+
}
12+
for (int i = 0; i < 26; ++i) {
13+
if ((cnt1[i] == 0) != (cnt2[i] == 0)) {
14+
return false;
15+
}
16+
}
17+
sort(cnt1, cnt1 + 26);
18+
sort(cnt2, cnt2 + 26);
19+
return equal(cnt1, cnt1 + 26, cnt2);
20+
}
2621
};

solution/1600-1699/1657.Determine if Two Strings Are Close/Solution.go

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,10 @@ func closeStrings(word1 string, word2 string) bool {
77
for _, c := range word2 {
88
cnt2[c-'a']++
99
}
10-
for i, v := range cnt1 {
11-
if (v > 0 && cnt2[i] == 0) || (v == 0 && cnt2[i] > 0) {
12-
return false
13-
}
10+
if !slices.EqualFunc(cnt1, cnt2, func(v1, v2 int) bool { return (v1 == 0) == (v2 == 0) }) {
11+
return false
1412
}
1513
sort.Ints(cnt1)
1614
sort.Ints(cnt2)
17-
for i, v := range cnt1 {
18-
if v != cnt2[i] {
19-
return false
20-
}
21-
}
22-
return true
15+
return slices.Equal(cnt1, cnt2)
2316
}
Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
1-
class Solution {
2-
public boolean closeStrings(String word1, String word2) {
3-
int[] cnt1 = new int[26];
4-
int[] cnt2 = new int[26];
5-
for (int i = 0; i < word1.length(); ++i) {
6-
++cnt1[word1.charAt(i) - 'a'];
7-
}
8-
for (int i = 0; i < word2.length(); ++i) {
9-
++cnt2[word2.charAt(i) - 'a'];
10-
}
11-
for (int i = 0; i < 26; ++i) {
12-
if ((cnt1[i] > 0 && cnt2[i] == 0) || (cnt2[i] > 0 && cnt1[i] == 0)) {
13-
return false;
14-
}
15-
}
16-
Arrays.sort(cnt1);
17-
Arrays.sort(cnt2);
18-
for (int i = 0; i < 26; ++i) {
19-
if (cnt1[i] != cnt2[i]) {
20-
return false;
21-
}
22-
}
23-
return true;
24-
}
1+
class Solution {
2+
public boolean closeStrings(String word1, String word2) {
3+
int[] cnt1 = new int[26];
4+
int[] cnt2 = new int[26];
5+
for (int i = 0; i < word1.length(); ++i) {
6+
++cnt1[word1.charAt(i) - 'a'];
7+
}
8+
for (int i = 0; i < word2.length(); ++i) {
9+
++cnt2[word2.charAt(i) - 'a'];
10+
}
11+
for (int i = 0; i < 26; ++i) {
12+
if ((cnt1[i] == 0) != (cnt2[i] == 0)) {
13+
return false;
14+
}
15+
}
16+
Arrays.sort(cnt1);
17+
Arrays.sort(cnt2);
18+
return Arrays.equals(cnt1, cnt2);
19+
}
2520
}
Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
class Solution:
2-
def closeStrings(self, word1: str, word2: str) -> bool:
3-
cnt1, cnt2 = Counter(word1), Counter(word2)
4-
return sorted(cnt1.values()) == sorted(cnt2.values()) and set(
5-
cnt1.keys()
6-
) == set(cnt2.keys())
1+
class Solution:
2+
def closeStrings(self, word1: str, word2: str) -> bool:
3+
cnt1 = Counter(word1)
4+
cnt2 = Counter(word2)
5+
return set(cnt1.keys()) == set(cnt2.keys()) and Counter(
6+
cnt1.values()
7+
) == Counter(cnt2.values())

0 commit comments

Comments
 (0)