@@ -79,37 +79,206 @@ strs 的列已经是按字典序排列了,所以我们不需要删除任何东
7979
8080<!-- solution:start -->
8181
82- ### 方法一
82+ ### 方法一:贪心
83+
84+ 字符串按字典序比较时,从左到右比较,第一个不相等的字符决定了两个字符串的大小关系。因此我们可以从左到右遍历每一列,判断当前列是否需要删除。
85+
86+ 我们维护一个长度为 $n - 1$ 的布尔数组 $\textit{st}$,表示相邻的字符串对是否已经确定了大小关系。如果已经确定了大小关系,那么后续在这两个字符串之间的任何字符比较都不会改变它们的大小关系。
87+
88+ 对于每一列 $j$,我们遍历所有相邻的字符串对 $(\textit{strs}[ i] , \textit{strs}[ i + 1] )$:
89+
90+ - 如果 $\textit{st}[ i] $ 为假且 $\textit{strs}[ i] [ j ] > \textit{strs}[ i + 1] [ j ] $,说明当前列必须删除,我们将答案加一并跳过该列的处理;
91+ - 否则,如果 $\textit{st}[ i] $ 为假且 $\textit{strs}[ i] [ j ] < \textit{strs}[ i + 1] [ j ] $,说明当前列确定了这两个字符串的大小关系,我们将 $\textit{st}[ i] $ 设为真。
92+
93+ 遍历完所有列后,答案即为需要删除的列数。
94+
95+ 这个贪心策略是最优的,因为字典序由从左到右第一个不同列决定。若当前列不删除且导致某对字符串顺序错误,则无论后续列如何,都无法修正这一错误,因此必须删除当前列。若当前列不删除且不导致任何字符串对顺序错误,则保留当前列不会影响最终的字典序关系。
96+
97+ 时间复杂度 $O(n \times m)$,空间复杂度 $O(n)$,其中 $n$ 和 $m$ 分别为字符串数组的长度和每个字符串的长度。
8398
8499<!-- tabs:start -->
85100
101+ #### Python3
102+
103+ ``` python
104+ class Solution :
105+ def minDeletionSize (self , strs : List[str ]) -> int :
106+ n = len (strs)
107+ m = len (strs[0 ])
108+ st = [False ] * (n - 1 )
109+ ans = 0
110+ for j in range (m):
111+ must_del = False
112+ for i in range (n - 1 ):
113+ if not st[i] and strs[i][j] > strs[i + 1 ][j]:
114+ must_del = True
115+ break
116+ if must_del:
117+ ans += 1
118+ else :
119+ for i in range (n - 1 ):
120+ if not st[i] and strs[i][j] < strs[i + 1 ][j]:
121+ st[i] = True
122+ return ans
123+ ```
124+
86125#### Java
87126
88127``` java
89128class Solution {
90- public int minDeletionSize (String [] A ) {
91- if (A == null || A . length <= 1 ) {
92- return 0 ;
129+ public int minDeletionSize (String [] strs ) {
130+ int n = strs. length;
131+ int m = strs[0 ]. length();
132+ boolean [] st = new boolean [n - 1 ];
133+ int ans = 0 ;
134+ for (int j = 0 ; j < m; ++ j) {
135+ boolean mustDel = false ;
136+ for (int i = 0 ; i < n - 1 ; ++ i) {
137+ if (! st[i] && strs[i]. charAt(j) > strs[i + 1 ]. charAt(j)) {
138+ mustDel = true ;
139+ break ;
140+ }
141+ }
142+ if (mustDel) {
143+ ++ ans;
144+ } else {
145+ for (int i = 0 ; i < n - 1 ; ++ i) {
146+ if (! st[i] && strs[i]. charAt(j) < strs[i + 1 ]. charAt(j)) {
147+ st[i] = true ;
148+ }
149+ }
150+ }
93151 }
94- int len = A . length, wordLen = A [0 ]. length(), res = 0 ;
95- boolean [] cut = new boolean [len];
96- search:
97- for (int j = 0 ; j < wordLen; j++ ) {
98- // 判断第 j 列是否应当保留
99- for (int i = 0 ; i < len - 1 ; i++ ) {
100- if (! cut[i] && A [i]. charAt(j) > A [i + 1 ]. charAt(j)) {
101- res += 1 ;
102- continue search;
152+ return ans;
153+ }
154+ }
155+ ```
156+
157+ #### C++
158+
159+ ``` cpp
160+ class Solution {
161+ public:
162+ int minDeletionSize(vector<string >& strs) {
163+ int n = strs.size();
164+ int m = strs[ 0] .size();
165+ vector<bool > st(n - 1, false);
166+ int ans = 0;
167+ for (int j = 0; j < m; ++j) {
168+ bool mustDel = false;
169+ for (int i = 0; i < n - 1; ++i) {
170+ if (!st[ i] && strs[ i] [ j ] > strs[ i + 1] [ j ] ) {
171+ mustDel = true;
172+ break;
103173 }
104174 }
105- // 更新 cut 的信息
106- for (int i = 0 ; i < len - 1 ; i++ ) {
107- if (A [i]. charAt(j) < A [i + 1 ]. charAt(j)) {
108- cut[i] = true ;
175+ if (mustDel) {
176+ ++ans;
177+ } else {
178+ for (int i = 0; i < n - 1; ++i) {
179+ if (!st[ i] && strs[ i] [ j ] < strs[ i + 1] [ j ] ) {
180+ st[ i] = true;
181+ }
109182 }
110183 }
111184 }
112- return res;
185+ return ans;
186+ }
187+ };
188+ ```
189+
190+ #### Go
191+
192+ ```go
193+ func minDeletionSize(strs []string) int {
194+ n := len(strs)
195+ m := len(strs[0])
196+ st := make([]bool, n-1)
197+ ans := 0
198+ for j := 0; j < m; j++ {
199+ mustDel := false
200+ for i := 0; i < n-1; i++ {
201+ if !st[i] && strs[i][j] > strs[i+1][j] {
202+ mustDel = true
203+ break
204+ }
205+ }
206+ if mustDel {
207+ ans++
208+ } else {
209+ for i := 0; i < n-1; i++ {
210+ if !st[i] && strs[i][j] < strs[i+1][j] {
211+ st[i] = true
212+ }
213+ }
214+ }
215+ }
216+ return ans
217+ }
218+ ```
219+
220+ #### TypeScript
221+
222+ ``` ts
223+ function minDeletionSize(strs : string []): number {
224+ const n = strs .length ;
225+ const m = strs [0 ].length ;
226+ const st: boolean [] = Array (n - 1 ).fill (false );
227+ let ans = 0 ;
228+
229+ for (let j = 0 ; j < m ; j ++ ) {
230+ let mustDel = false ;
231+ for (let i = 0 ; i < n - 1 ; i ++ ) {
232+ if (! st [i ] && strs [i ][j ] > strs [i + 1 ][j ]) {
233+ mustDel = true ;
234+ break ;
235+ }
236+ }
237+ if (mustDel ) {
238+ ans ++ ;
239+ } else {
240+ for (let i = 0 ; i < n - 1 ; i ++ ) {
241+ if (! st [i ] && strs [i ][j ] < strs [i + 1 ][j ]) {
242+ st [i ] = true ;
243+ }
244+ }
245+ }
246+ }
247+
248+ return ans ;
249+ }
250+ ```
251+
252+ #### Rust
253+
254+ ``` rust
255+ impl Solution {
256+ pub fn min_deletion_size (strs : Vec <String >) -> i32 {
257+ let n = strs . len ();
258+ let m = strs [0 ]. len ();
259+ let mut st = vec! [false ; n - 1 ];
260+ let mut ans = 0 ;
261+
262+ for j in 0 .. m {
263+ let mut must_del = false ;
264+ for i in 0 .. n - 1 {
265+ if ! st [i ] && strs [i ]. as_bytes ()[j ] > strs [i + 1 ]. as_bytes ()[j ] {
266+ must_del = true ;
267+ break ;
268+ }
269+ }
270+ if must_del {
271+ ans += 1 ;
272+ } else {
273+ for i in 0 .. n - 1 {
274+ if ! st [i ] && strs [i ]. as_bytes ()[j ] < strs [i + 1 ]. as_bytes ()[j ] {
275+ st [i ] = true ;
276+ }
277+ }
278+ }
279+ }
280+
281+ ans
113282 }
114283}
115284```
0 commit comments