@@ -101,32 +101,231 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3500-3599/3598.Lo
101101
102102<!-- solution:start -->
103103
104- ### 方法一
104+ ### 方法一:有序集合
105+
106+ 我们定义一个函数 $\textit{calc}(s, t)$,它计算字符串 $s$ 和 $t$ 的最长公共前缀的长度。我们可以使用有序集合来维护所有相邻字符串对的最长公共前缀长度。
107+
108+ 定义一个函数 $\textit{add}(i, j)$,它将下标 $i$ 和 $j$ 处的字符串对的最长公共前缀长度添加到有序集合中。定义一个函数 $\textit{remove}(i, j)$,它从有序集合中移除下标 $i$ 和 $j$ 处的字符串对的最长公共前缀长度。
109+
110+ 我们首先计算所有相邻字符串对的最长公共前缀长度,并将其存储在有序集合中。然后,我们遍历每个下标 $i$,执行以下操作:
111+
112+ 1 . 移除下标 $i$ 和 $i + 1$ 处的字符串对的最长公共前缀长度。
113+ 2 . 移除下标 $i - 1$ 和 $i$ 处的字符串对的最长公共前缀长度。
114+ 3 . 添加下标 $i - 1$ 和 $i + 1$ 处的字符串对的最长公共前缀长度。
115+ 4 . 将当前有序集合中的最大值(如果存在且大于 0)添加到答案中。
116+ 5 . 移除下标 $i - 1$ 和 $i + 1$ 处的字符串对的最长公共前缀长度。
117+ 6 . 添加下标 $i - 1$ 和 $i$ 处的字符串对的最长公共前缀长度。
118+ 7 . 添加下标 $i$ 和 $i + 1$ 处的字符串对的最长公共前缀长度。
119+
120+ 这样,我们可以在每次移除一个字符串后,快速计算出相邻字符串对的最长公共前缀长度。
121+
122+ 时间复杂度 $O(L + n \times \log n)$,空间复杂度 $O(n)$,其中 $L$ 是所有字符串的总长度,而 $n$ 是字符串的数量。
105123
106124<!-- tabs:start -->
107125
108126#### Python3
109127
110128``` python
111-
129+ class Solution :
130+ def longestCommonPrefix (self , words : List[str ]) -> List[int ]:
131+ @cache
132+ def calc (s : str , t : str ) -> int :
133+ k = 0
134+ for a, b in zip (s, t):
135+ if a != b:
136+ break
137+ k += 1
138+ return k
139+
140+ def add (i : int , j : int ):
141+ if 0 <= i < n and 0 <= j < n:
142+ sl.add(calc(words[i], words[j]))
143+
144+ def remove (i : int , j : int ):
145+ if 0 <= i < n and 0 <= j < n:
146+ sl.remove(calc(words[i], words[j]))
147+
148+ n = len (words)
149+ sl = SortedList(calc(a, b) for a, b in pairwise(words))
150+ ans = []
151+ for i in range (n):
152+ remove(i, i + 1 )
153+ remove(i - 1 , i)
154+ add(i - 1 , i + 1 )
155+ ans.append(sl[- 1 ] if sl and sl[- 1 ] > 0 else 0 )
156+ remove(i - 1 , i + 1 )
157+ add(i - 1 , i)
158+ add(i, i + 1 )
159+ return ans
112160```
113161
114162#### Java
115163
116164``` java
117-
165+ class Solution {
166+ private final TreeMap<Integer , Integer > tm = new TreeMap<> ();
167+ private String [] words;
168+ private int n;
169+
170+ public int [] longestCommonPrefix (String [] words ) {
171+ n = words. length;
172+ this . words = words;
173+ for (int i = 0 ; i + 1 < n; ++ i) {
174+ tm. merge(calc(words[i], words[i + 1 ]), 1 , Integer :: sum);
175+ }
176+ int [] ans = new int [n];
177+ for (int i = 0 ; i < n; ++ i) {
178+ remove(i, i + 1 );
179+ remove(i - 1 , i);
180+ add(i - 1 , i + 1 );
181+ ans[i] = ! tm. isEmpty() && tm. lastKey() > 0 ? tm. lastKey() : 0 ;
182+ remove(i - 1 , i + 1 );
183+ add(i - 1 , i);
184+ add(i, i + 1 );
185+ }
186+ return ans;
187+ }
188+
189+ private void add (int i , int j ) {
190+ if (i >= 0 && i < n && j >= 0 && j < n) {
191+ tm. merge(calc(words[i], words[j]), 1 , Integer :: sum);
192+ }
193+ }
194+
195+ private void remove (int i , int j ) {
196+ if (i >= 0 && i < n && j >= 0 && j < n) {
197+ int x = calc(words[i], words[j]);
198+ if (tm. merge(x, - 1 , Integer :: sum) == 0 ) {
199+ tm. remove(x);
200+ }
201+ }
202+ }
203+
204+ private int calc (String s , String t ) {
205+ int m = Math . min(s. length(), t. length());
206+ for (int k = 0 ; k < m; ++ k) {
207+ if (s. charAt(k) != t. charAt(k)) {
208+ return k;
209+ }
210+ }
211+ return m;
212+ }
213+ }
118214```
119215
120216#### C++
121217
122218``` cpp
123-
219+ class Solution {
220+ public:
221+ vector<int > longestCommonPrefix(vector<string >& words) {
222+ multiset<int > ms;
223+ int n = words.size();
224+ auto calc = [ &] (const string& s, const string& t) {
225+ int m = min(s.size(), t.size());
226+ for (int k = 0; k < m; ++k) {
227+ if (s[ k] != t[ k] ) {
228+ return k;
229+ }
230+ }
231+ return m;
232+ };
233+ for (int i = 0; i + 1 < n; ++i) {
234+ ms.insert(calc(words[ i] , words[ i + 1] ));
235+ }
236+ vector<int > ans(n);
237+ auto add = [ &] (int i, int j) {
238+ if (i >= 0 && i < n && j >= 0 && j < n) {
239+ ms.insert(calc(words[ i] , words[ j] ));
240+ }
241+ };
242+ auto remove = [ &] (int i, int j) {
243+ if (i >= 0 && i < n && j >= 0 && j < n) {
244+ int x = calc(words[ i] , words[ j] );
245+ auto it = ms.find(x);
246+ if (it != ms.end()) {
247+ ms.erase(it);
248+ }
249+ }
250+ };
251+ for (int i = 0; i < n; ++i) {
252+ remove(i, i + 1);
253+ remove(i - 1, i);
254+ add(i - 1, i + 1);
255+ ans[ i] = ms.empty() ? 0 : * ms.rbegin();
256+ remove(i - 1, i + 1);
257+ add(i - 1, i);
258+ add(i, i + 1);
259+ }
260+ return ans;
261+ }
262+ };
124263```
125264
126265#### Go
127266
128267```go
129-
268+ func longestCommonPrefix(words []string) []int {
269+ n := len(words)
270+ tm := treemap.NewWithIntComparator()
271+
272+ calc := func(s, t string) int {
273+ m := min(len(s), len(t))
274+ for k := 0; k < m; k++ {
275+ if s[k] != t[k] {
276+ return k
277+ }
278+ }
279+ return m
280+ }
281+
282+ add := func(i, j int) {
283+ if i >= 0 && i < n && j >= 0 && j < n {
284+ x := calc(words[i], words[j])
285+ if v, ok := tm.Get(x); ok {
286+ tm.Put(x, v.(int)+1)
287+ } else {
288+ tm.Put(x, 1)
289+ }
290+ }
291+ }
292+
293+ remove := func(i, j int) {
294+ if i >= 0 && i < n && j >= 0 && j < n {
295+ x := calc(words[i], words[j])
296+ if v, ok := tm.Get(x); ok {
297+ if v.(int) == 1 {
298+ tm.Remove(x)
299+ } else {
300+ tm.Put(x, v.(int)-1)
301+ }
302+ }
303+ }
304+ }
305+
306+ for i := 0; i+1 < n; i++ {
307+ add(i, i+1)
308+ }
309+
310+ ans := make([]int, n)
311+ for i := 0; i < n; i++ {
312+ remove(i, i+1)
313+ remove(i-1, i)
314+ add(i-1, i+1)
315+
316+ if !tm.Empty() {
317+ if maxKey, _ := tm.Max(); maxKey.(int) > 0 {
318+ ans[i] = maxKey.(int)
319+ }
320+ }
321+
322+ remove(i-1, i+1)
323+ add(i-1, i)
324+ add(i, i+1)
325+ }
326+
327+ return ans
328+ }
130329```
131330
132331<!-- tabs: end -->
0 commit comments