47
47
48
48
<!-- 这里可写通用的实现逻辑 -->
49
49
50
- ** 朴素解法: **
50
+ ** 方法一:哈希表 **
51
51
52
- 给对应的字符打上印记,使用该字符首次出现的索引位置作为印记值,使用哈希表记录 。
52
+ 我们先将字符串 $s$ 按照空格分割成单词数组 $ws$,如果 $pattern$ 和 $ws$ 的长度不相等,直接返回 ` false ` 。否则,我们使用两个哈希表 $d_1$ 和 $d_2$,分别记录 $pattern$ 和 $ws$ 中每个字符和单词的对应关系 。
53
53
54
- 而后,将字符串转换为对应的索引数组,如 ` pattern = "abbac" ` ,转换后为 ` [0, 1, 1, 0, 4] ` 。对于字符串 ` s ` 同理 。
54
+ 接下来,我们遍历 $ pattern$ 和 $ws$,对于每个字符 $a$ 和单词 $b$,如果 $d_1$ 中存在 $a$ 的映射,且映射的单词不是 $b$,或者 $d_2$ 中存在 $b$ 的映射,且映射的字符不是 $a$,则返回 ` false ` 。否则,我们将 $a$ 和 $b$ 的映射分别加入 $d_1$ 和 $d_2$ 中 。
55
55
56
- > 需注意, ` pattern ` 以 ` char ` 为 ` key ` ;而 ` s ` 则是以 ` ' ' ` 作为分割符,转换为字符串数组之后,以成员 ` String ` 为 ` key ` 。
56
+ 遍历结束后,返回 ` true ` 。
57
57
58
- 对比两个索引数组,在所有成员一一对应的情况下,才能表示两者规律一致。
59
-
60
- 优化:
61
-
62
- 转换为索引数组方便理解,但是太浪费。
63
-
64
- 可以选择再次遍历字符串,以 ` key ` 取值对比即可。
58
+ 时间复杂度 $O(m + n)$,空间复杂度 $O(m + n)$。其中 $m$ 和 $n$ 分别是 $pattern$ 和字符串 $s$ 的长度。
65
59
66
60
<!-- tabs:start -->
67
61
72
66
``` python
73
67
class Solution :
74
68
def wordPattern (self , pattern : str , s : str ) -> bool :
75
- s = s.split(' ' )
76
- n = len (pattern)
77
- if n != len (s):
69
+ ws = s.split()
70
+ if len (pattern) != len (ws):
78
71
return False
79
- c2str, str2c = defaultdict(), defaultdict()
80
- for i in range (n):
81
- k, v = pattern[i], s[i]
82
- if k in c2str and c2str[k] != v:
83
- return False
84
- if v in str2c and str2c[v] != k:
72
+ d1 = {}
73
+ d2 = {}
74
+ for a, b in zip (pattern, ws):
75
+ if (a in d1 and d1[a] != b) or (b in d2 and d2[b] != a):
85
76
return False
86
- c2str[k], str2c[v] = v, k
77
+ d1[a] = b
78
+ d2[b] = a
87
79
return True
88
80
```
89
81
@@ -94,99 +86,50 @@ class Solution:
94
86
``` java
95
87
class Solution {
96
88
public boolean wordPattern (String pattern , String s ) {
97
- String [] ss = s. split(" " );
98
- int n = pattern. length();
99
- if (n != ss. length) {
89
+ String [] ws = s. split(" " );
90
+ if (pattern. length() != ws. length) {
100
91
return false ;
101
92
}
102
- Map<Character , String > c2str = new HashMap<> ();
103
- Map<String , Character > str2c = new HashMap<> ();
104
- for (int i = 0 ; i < n ; ++ i) {
105
- char k = pattern. charAt(i);
106
- String v = ss [i];
107
- if (c2str . containsKey(k) && ! Objects . equals(c2str . get(k), v) ) {
93
+ Map<Character , String > d1 = new HashMap<> ();
94
+ Map<String , Character > d2 = new HashMap<> ();
95
+ for (int i = 0 ; i < ws . length ; ++ i) {
96
+ char a = pattern. charAt(i);
97
+ String b = ws [i];
98
+ if (! d1 . getOrDefault(a, b) . equals(b) || d2 . getOrDefault(b, a) != a ) {
108
99
return false ;
109
100
}
110
- if (str2c. containsKey(v) && ! Objects . equals(str2c. get(v), k)) {
111
- return false ;
112
- }
113
- c2str. put(k, v);
114
- str2c. put(v, k);
101
+ d1. put(a, b);
102
+ d2. put(b, a);
115
103
}
116
104
return true ;
117
105
}
118
106
}
119
107
```
120
108
121
- ### ** TypeScript**
122
-
123
- ``` ts
124
- function wordPattern(pattern : string , s : string ): boolean {
125
- let n = pattern .length ;
126
- let values = s .split (' ' );
127
- if (n != values .length ) return false ;
128
- let table = new Array (128 );
129
- for (let i = 0 ; i < n ; i ++ ) {
130
- let k = pattern .charCodeAt (i ),
131
- v = values [i ];
132
- if (! table [k ]) {
133
- if (table .includes (v )) return false ;
134
- table [k ] = v ;
135
- } else {
136
- if (table [k ] != v ) return false ;
137
- }
138
- }
139
- return true ;
140
- }
141
- ```
142
-
143
- ``` ts
144
- function wordPattern(pattern : string , s : string ): boolean {
145
- const n = pattern .length ;
146
- const cs = s .split (' ' );
147
- if (n !== cs .length ) {
148
- return false ;
149
- }
150
- const map1 = new Map <string , number >();
151
- const map2 = new Map <string , number >();
152
- for (let i = 0 ; i < n ; i ++ ) {
153
- const c1 = pattern [i ];
154
- const c2 = cs [i ];
155
- if (! map1 .has (c1 )) {
156
- map1 .set (c1 , i );
157
- }
158
- if (! map2 .has (c2 )) {
159
- map2 .set (c2 , i );
160
- }
161
- if (map1 .get (c1 ) !== map2 .get (c2 )) {
162
- return false ;
163
- }
164
- }
165
- return true ;
166
- }
167
- ```
168
-
169
109
### ** C++**
170
110
171
111
``` cpp
172
112
class Solution {
173
113
public:
174
114
bool wordPattern(string pattern, string s) {
175
115
istringstream is(s);
176
- vector<string > ss;
177
- while (is >> s) ss.push_back(s);
178
- int n = pattern.size();
179
- if (n != ss.size()) return false;
180
-
181
- unordered_map<char, string> c2str;
182
- unordered_map<string, char> str2c;
183
- for (int i = 0; i < n; ++i) {
184
- char k = pattern[i];
185
- string v = ss[i];
186
- if (c2str.count(k) && c2str[k] != v) return false;
187
- if (str2c.count(v) && str2c[v] != k) return false;
188
- c2str[k] = v;
189
- str2c[v] = k;
116
+ vector<string > ws;
117
+ while (is >> s) {
118
+ ws.push_back(s);
119
+ }
120
+ if (pattern.size() != ws.size()) {
121
+ return false;
122
+ }
123
+ unordered_map<char, string> d1;
124
+ unordered_map<string, char> d2;
125
+ for (int i = 0; i < ws.size(); ++i) {
126
+ char a = pattern[ i] ;
127
+ string b = ws[ i] ;
128
+ if ((d1.count(a) && d1[ a] != b) || (d2.count(b) && d2[ b] != a)) {
129
+ return false;
130
+ }
131
+ d1[ a] = b;
132
+ d2[ b] = a;
190
133
}
191
134
return true;
192
135
}
@@ -197,27 +140,81 @@ public:
197
140
198
141
```go
199
142
func wordPattern(pattern string, s string) bool {
200
- ss := strings.Split (s, " " )
201
- n := len (pattern)
202
- if n != len (ss) {
143
+ ws := strings.Split(s, " ")
144
+ if len(ws) != len(pattern) {
203
145
return false
204
146
}
205
- c2str := make ( map [byte ]string )
206
- str2c := make ( map [string ]byte )
207
- for i := 0 ; i < n; i++ {
208
- k , v := pattern[i], ss [i]
209
- if c2str[k] != " " && c2str[k] != v {
147
+ d1 := map[rune ]string{}
148
+ d2 := map[string]rune{}
149
+ for i, a := range pattern {
150
+ b := ws [i]
151
+ if v, ok := d1[a]; ok && v != b {
210
152
return false
211
153
}
212
- if str2c[v] > 0 && str2c[v] != k {
154
+ if v, ok := d2[b]; ok && v != a {
213
155
return false
214
156
}
215
- c2str[k], str2c[v] = v, k
157
+ d1[a] = b
158
+ d2[b] = a
216
159
}
217
160
return true
218
161
}
219
162
```
220
163
164
+ ### ** TypeScript**
165
+
166
+ ``` ts
167
+ function wordPattern(pattern : string , s : string ): boolean {
168
+ const ws = s .split (' ' );
169
+ if (pattern .length !== ws .length ) {
170
+ return false ;
171
+ }
172
+ const d1 = new Map <string , string >();
173
+ const d2 = new Map <string , string >();
174
+ for (let i = 0 ; i < pattern .length ; ++ i ) {
175
+ const a = pattern [i ];
176
+ const b = ws [i ];
177
+ if (d1 .has (a ) && d1 .get (a ) !== b ) {
178
+ return false ;
179
+ }
180
+ if (d2 .has (b ) && d2 .get (b ) !== a ) {
181
+ return false ;
182
+ }
183
+ d1 .set (a , b );
184
+ d2 .set (b , a );
185
+ }
186
+ return true ;
187
+ }
188
+ ```
189
+
190
+ ### ** C#**
191
+
192
+ ``` cs
193
+ public class Solution {
194
+ public bool WordPattern (string pattern , string s ) {
195
+ var ws = s .Split (' ' );
196
+ if (pattern .Length != ws .Length ) {
197
+ return false ;
198
+ }
199
+ var d1 = new Dictionary <char , string >();
200
+ var d2 = new Dictionary <string , char >();
201
+ for (int i = 0 ; i < ws .Length ; ++ i ) {
202
+ var a = pattern [i ];
203
+ var b = ws [i ];
204
+ if (d1 .ContainsKey (a ) && d1 [a ] != b ) {
205
+ return false ;
206
+ }
207
+ if (d2 .ContainsKey (b ) && d2 [b ] != a ) {
208
+ return false ;
209
+ }
210
+ d1 [a ] = b ;
211
+ d2 [b ] = a ;
212
+ }
213
+ return true ;
214
+ }
215
+ }
216
+ ```
217
+
221
218
### ** Rust**
222
219
223
220
``` rust
0 commit comments