diff --git a/solution/0900-0999/0955.Delete Columns to Make Sorted II/README.md b/solution/0900-0999/0955.Delete Columns to Make Sorted II/README.md index 8251dba9e5625..9f6da98c0f0af 100644 --- a/solution/0900-0999/0955.Delete Columns to Make Sorted II/README.md +++ b/solution/0900-0999/0955.Delete Columns to Make Sorted II/README.md @@ -79,37 +79,206 @@ strs 的列已经是按字典序排列了,所以我们不需要删除任何东 -### 方法一 +### 方法一:贪心 + +字符串按字典序比较时,从左到右比较,第一个不相等的字符决定了两个字符串的大小关系。因此我们可以从左到右遍历每一列,判断当前列是否需要删除。 + +我们维护一个长度为 $n - 1$ 的布尔数组 $\textit{st}$,表示相邻的字符串对是否已经确定了大小关系。如果已经确定了大小关系,那么后续在这两个字符串之间的任何字符比较都不会改变它们的大小关系。 + +对于每一列 $j$,我们遍历所有相邻的字符串对 $(\textit{strs}[i], \textit{strs}[i + 1])$: + +- 如果 $\textit{st}[i]$ 为假且 $\textit{strs}[i][j] > \textit{strs}[i + 1][j]$,说明当前列必须删除,我们将答案加一并跳过该列的处理; +- 否则,如果 $\textit{st}[i]$ 为假且 $\textit{strs}[i][j] < \textit{strs}[i + 1][j]$,说明当前列确定了这两个字符串的大小关系,我们将 $\textit{st}[i]$ 设为真。 + +遍历完所有列后,答案即为需要删除的列数。 + +这个贪心策略是最优的,因为字典序由从左到右第一个不同列决定。若当前列不删除且导致某对字符串顺序错误,则无论后续列如何,都无法修正这一错误,因此必须删除当前列。若当前列不删除且不导致任何字符串对顺序错误,则保留当前列不会影响最终的字典序关系。 + +时间复杂度 $O(n \times m)$,空间复杂度 $O(n)$,其中 $n$ 和 $m$ 分别为字符串数组的长度和每个字符串的长度。 +#### Python3 + +```python +class Solution: + def minDeletionSize(self, strs: List[str]) -> int: + n = len(strs) + m = len(strs[0]) + st = [False] * (n - 1) + ans = 0 + for j in range(m): + must_del = False + for i in range(n - 1): + if not st[i] and strs[i][j] > strs[i + 1][j]: + must_del = True + break + if must_del: + ans += 1 + else: + for i in range(n - 1): + if not st[i] and strs[i][j] < strs[i + 1][j]: + st[i] = True + return ans +``` + #### Java ```java class Solution { - public int minDeletionSize(String[] A) { - if (A == null || A.length <= 1) { - return 0; + public int minDeletionSize(String[] strs) { + int n = strs.length; + int m = strs[0].length(); + boolean[] st = new boolean[n - 1]; + int ans = 0; + for (int j = 0; j < m; ++j) { + boolean mustDel = false; + for (int i = 0; i < n - 1; ++i) { + if (!st[i] && strs[i].charAt(j) > strs[i + 1].charAt(j)) { + mustDel = true; + break; + } + } + if (mustDel) { + ++ans; + } else { + for (int i = 0; i < n - 1; ++i) { + if (!st[i] && strs[i].charAt(j) < strs[i + 1].charAt(j)) { + st[i] = true; + } + } + } } - int len = A.length, wordLen = A[0].length(), res = 0; - boolean[] cut = new boolean[len]; - search: - for (int j = 0; j < wordLen; j++) { - // 判断第 j 列是否应当保留 - for (int i = 0; i < len - 1; i++) { - if (!cut[i] && A[i].charAt(j) > A[i + 1].charAt(j)) { - res += 1; - continue search; + return ans; + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + int minDeletionSize(vector& strs) { + int n = strs.size(); + int m = strs[0].size(); + vector st(n - 1, false); + int ans = 0; + for (int j = 0; j < m; ++j) { + bool mustDel = false; + for (int i = 0; i < n - 1; ++i) { + if (!st[i] && strs[i][j] > strs[i + 1][j]) { + mustDel = true; + break; } } - // 更新 cut 的信息 - for (int i = 0; i < len - 1; i++) { - if (A[i].charAt(j) < A[i + 1].charAt(j)) { - cut[i] = true; + if (mustDel) { + ++ans; + } else { + for (int i = 0; i < n - 1; ++i) { + if (!st[i] && strs[i][j] < strs[i + 1][j]) { + st[i] = true; + } } } } - return res; + return ans; + } +}; +``` + +#### Go + +```go +func minDeletionSize(strs []string) int { + n := len(strs) + m := len(strs[0]) + st := make([]bool, n-1) + ans := 0 + for j := 0; j < m; j++ { + mustDel := false + for i := 0; i < n-1; i++ { + if !st[i] && strs[i][j] > strs[i+1][j] { + mustDel = true + break + } + } + if mustDel { + ans++ + } else { + for i := 0; i < n-1; i++ { + if !st[i] && strs[i][j] < strs[i+1][j] { + st[i] = true + } + } + } + } + return ans +} +``` + +#### TypeScript + +```ts +function minDeletionSize(strs: string[]): number { + const n = strs.length; + const m = strs[0].length; + const st: boolean[] = Array(n - 1).fill(false); + let ans = 0; + + for (let j = 0; j < m; j++) { + let mustDel = false; + for (let i = 0; i < n - 1; i++) { + if (!st[i] && strs[i][j] > strs[i + 1][j]) { + mustDel = true; + break; + } + } + if (mustDel) { + ans++; + } else { + for (let i = 0; i < n - 1; i++) { + if (!st[i] && strs[i][j] < strs[i + 1][j]) { + st[i] = true; + } + } + } + } + + return ans; +} +``` + +#### Rust + +```rust +impl Solution { + pub fn min_deletion_size(strs: Vec) -> i32 { + let n = strs.len(); + let m = strs[0].len(); + let mut st = vec![false; n - 1]; + let mut ans = 0; + + for j in 0..m { + let mut must_del = false; + for i in 0..n - 1 { + if !st[i] && strs[i].as_bytes()[j] > strs[i + 1].as_bytes()[j] { + must_del = true; + break; + } + } + if must_del { + ans += 1; + } else { + for i in 0..n - 1 { + if !st[i] && strs[i].as_bytes()[j] < strs[i + 1].as_bytes()[j] { + st[i] = true; + } + } + } + } + + ans } } ``` diff --git a/solution/0900-0999/0955.Delete Columns to Make Sorted II/README_EN.md b/solution/0900-0999/0955.Delete Columns to Make Sorted II/README_EN.md index 2ea72230eb55e..588ae337ea53e 100644 --- a/solution/0900-0999/0955.Delete Columns to Make Sorted II/README_EN.md +++ b/solution/0900-0999/0955.Delete Columns to Make Sorted II/README_EN.md @@ -32,7 +32,7 @@ tags:
 Input: strs = ["ca","bb","ac"]
 Output: 1
-Explanation: 
+Explanation:
 After deleting the first column, strs = ["a", "b", "c"].
 Now strs is in lexicographic order (ie. strs[0] <= strs[1] <= strs[2]).
 We require at least 1 deletion since initially strs was not in lexicographic order, so the answer is 1.
@@ -43,7 +43,7 @@ We require at least 1 deletion since initially strs was not in lexicographic ord
 
 Input: strs = ["xc","yb","za"]
 Output: 0
-Explanation: 
+Explanation:
 strs is already in lexicographic order, so we do not need to delete anything.
 Note that the rows of strs are not necessarily in lexicographic order:
 i.e., it is NOT necessarily true that (strs[0][0] <= strs[0][1] <= ...)
@@ -73,37 +73,206 @@ i.e., it is NOT necessarily true that (strs[0][0] <= strs[0][1] <= ...)
 
 
 
-### Solution 1
+### Solution 1: Greedy
+
+When comparing strings in lexicographical order, we compare from left to right, and the first unequal character determines the ordering relationship between two strings. Therefore, we can traverse each column from left to right and determine whether the current column needs to be deleted.
+
+We maintain a boolean array $\textit{st}$ of length $n - 1$, indicating whether the ordering relationship between adjacent string pairs has been determined. If the ordering relationship has been determined, then any subsequent character comparison between these two strings will not change their ordering relationship.
+
+For each column $j$, we traverse all adjacent string pairs $(\textit{strs}[i], \textit{strs}[i + 1])$:
+
+-   If $\textit{st}[i]$ is false and $\textit{strs}[i][j] > \textit{strs}[i + 1][j]$, it means the current column must be deleted. We increment the answer by one and skip processing this column;
+-   Otherwise, if $\textit{st}[i]$ is false and $\textit{strs}[i][j] < \textit{strs}[i + 1][j]$, it means the current column determines the ordering relationship between these two strings. We set $\textit{st}[i]$ to true.
+
+After traversing all columns, the answer is the number of columns that need to be deleted.
+
+This greedy strategy is optimal because lexicographical order is determined by the first different column from left to right. If the current column is not deleted and causes incorrect ordering for some string pair, then regardless of subsequent columns, this error cannot be corrected, so the current column must be deleted. If the current column is not deleted and does not cause incorrect ordering for any string pair, then keeping the current column will not affect the final lexicographical ordering relationship.
+
+The time complexity is $O(n \times m)$ and the space complexity is $O(n)$, where $n$ and $m$ are the length of the string array and the length of each string, respectively.
 
 
 
+#### Python3
+
+```python
+class Solution:
+    def minDeletionSize(self, strs: List[str]) -> int:
+        n = len(strs)
+        m = len(strs[0])
+        st = [False] * (n - 1)
+        ans = 0
+        for j in range(m):
+            must_del = False
+            for i in range(n - 1):
+                if not st[i] and strs[i][j] > strs[i + 1][j]:
+                    must_del = True
+                    break
+            if must_del:
+                ans += 1
+            else:
+                for i in range(n - 1):
+                    if not st[i] and strs[i][j] < strs[i + 1][j]:
+                        st[i] = True
+        return ans
+```
+
 #### Java
 
 ```java
 class Solution {
-    public int minDeletionSize(String[] A) {
-        if (A == null || A.length <= 1) {
-            return 0;
+    public int minDeletionSize(String[] strs) {
+        int n = strs.length;
+        int m = strs[0].length();
+        boolean[] st = new boolean[n - 1];
+        int ans = 0;
+        for (int j = 0; j < m; ++j) {
+            boolean mustDel = false;
+            for (int i = 0; i < n - 1; ++i) {
+                if (!st[i] && strs[i].charAt(j) > strs[i + 1].charAt(j)) {
+                    mustDel = true;
+                    break;
+                }
+            }
+            if (mustDel) {
+                ++ans;
+            } else {
+                for (int i = 0; i < n - 1; ++i) {
+                    if (!st[i] && strs[i].charAt(j) < strs[i + 1].charAt(j)) {
+                        st[i] = true;
+                    }
+                }
+            }
         }
-        int len = A.length, wordLen = A[0].length(), res = 0;
-        boolean[] cut = new boolean[len];
-    search:
-        for (int j = 0; j < wordLen; j++) {
-            // 判断第 j 列是否应当保留
-            for (int i = 0; i < len - 1; i++) {
-                if (!cut[i] && A[i].charAt(j) > A[i + 1].charAt(j)) {
-                    res += 1;
-                    continue search;
+        return ans;
+    }
+}
+```
+
+#### C++
+
+```cpp
+class Solution {
+public:
+    int minDeletionSize(vector& strs) {
+        int n = strs.size();
+        int m = strs[0].size();
+        vector st(n - 1, false);
+        int ans = 0;
+        for (int j = 0; j < m; ++j) {
+            bool mustDel = false;
+            for (int i = 0; i < n - 1; ++i) {
+                if (!st[i] && strs[i][j] > strs[i + 1][j]) {
+                    mustDel = true;
+                    break;
                 }
             }
-            // 更新 cut 的信息
-            for (int i = 0; i < len - 1; i++) {
-                if (A[i].charAt(j) < A[i + 1].charAt(j)) {
-                    cut[i] = true;
+            if (mustDel) {
+                ++ans;
+            } else {
+                for (int i = 0; i < n - 1; ++i) {
+                    if (!st[i] && strs[i][j] < strs[i + 1][j]) {
+                        st[i] = true;
+                    }
                 }
             }
         }
-        return res;
+        return ans;
+    }
+};
+```
+
+#### Go
+
+```go
+func minDeletionSize(strs []string) int {
+	n := len(strs)
+	m := len(strs[0])
+	st := make([]bool, n-1)
+	ans := 0
+	for j := 0; j < m; j++ {
+		mustDel := false
+		for i := 0; i < n-1; i++ {
+			if !st[i] && strs[i][j] > strs[i+1][j] {
+				mustDel = true
+				break
+			}
+		}
+		if mustDel {
+			ans++
+		} else {
+			for i := 0; i < n-1; i++ {
+				if !st[i] && strs[i][j] < strs[i+1][j] {
+					st[i] = true
+				}
+			}
+		}
+	}
+	return ans
+}
+```
+
+#### TypeScript
+
+```ts
+function minDeletionSize(strs: string[]): number {
+    const n = strs.length;
+    const m = strs[0].length;
+    const st: boolean[] = Array(n - 1).fill(false);
+    let ans = 0;
+
+    for (let j = 0; j < m; j++) {
+        let mustDel = false;
+        for (let i = 0; i < n - 1; i++) {
+            if (!st[i] && strs[i][j] > strs[i + 1][j]) {
+                mustDel = true;
+                break;
+            }
+        }
+        if (mustDel) {
+            ans++;
+        } else {
+            for (let i = 0; i < n - 1; i++) {
+                if (!st[i] && strs[i][j] < strs[i + 1][j]) {
+                    st[i] = true;
+                }
+            }
+        }
+    }
+
+    return ans;
+}
+```
+
+#### Rust
+
+```rust
+impl Solution {
+    pub fn min_deletion_size(strs: Vec) -> i32 {
+        let n = strs.len();
+        let m = strs[0].len();
+        let mut st = vec![false; n - 1];
+        let mut ans = 0;
+
+        for j in 0..m {
+            let mut must_del = false;
+            for i in 0..n - 1 {
+                if !st[i] && strs[i].as_bytes()[j] > strs[i + 1].as_bytes()[j] {
+                    must_del = true;
+                    break;
+                }
+            }
+            if must_del {
+                ans += 1;
+            } else {
+                for i in 0..n - 1 {
+                    if !st[i] && strs[i].as_bytes()[j] < strs[i + 1].as_bytes()[j] {
+                        st[i] = true;
+                    }
+                }
+            }
+        }
+
+        ans
     }
 }
 ```
diff --git a/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.cpp b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.cpp
new file mode 100644
index 0000000000000..d9529904dc436
--- /dev/null
+++ b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.cpp	
@@ -0,0 +1,28 @@
+class Solution {
+public:
+    int minDeletionSize(vector& strs) {
+        int n = strs.size();
+        int m = strs[0].size();
+        vector st(n - 1, false);
+        int ans = 0;
+        for (int j = 0; j < m; ++j) {
+            bool must_del = false;
+            for (int i = 0; i < n - 1; ++i) {
+                if (!st[i] && strs[i][j] > strs[i + 1][j]) {
+                    must_del = true;
+                    break;
+                }
+            }
+            if (must_del) {
+                ++ans;
+            } else {
+                for (int i = 0; i < n - 1; ++i) {
+                    if (!st[i] && strs[i][j] < strs[i + 1][j]) {
+                        st[i] = true;
+                    }
+                }
+            }
+        }
+        return ans;
+    }
+};
diff --git a/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.go b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.go
new file mode 100644
index 0000000000000..bc8221b881b8e
--- /dev/null
+++ b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.go	
@@ -0,0 +1,25 @@
+func minDeletionSize(strs []string) int {
+	n := len(strs)
+	m := len(strs[0])
+	st := make([]bool, n-1)
+	ans := 0
+	for j := 0; j < m; j++ {
+		mustDel := false
+		for i := 0; i < n-1; i++ {
+			if !st[i] && strs[i][j] > strs[i+1][j] {
+				mustDel = true
+				break
+			}
+		}
+		if mustDel {
+			ans++
+		} else {
+			for i := 0; i < n-1; i++ {
+				if !st[i] && strs[i][j] < strs[i+1][j] {
+					st[i] = true
+				}
+			}
+		}
+	}
+	return ans
+}
diff --git a/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.java b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.java
index 976667ec3f36d..79069340dcc6a 100644
--- a/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.java	
+++ b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.java	
@@ -1,26 +1,27 @@
 class Solution {
-    public int minDeletionSize(String[] A) {
-        if (A == null || A.length <= 1) {
-            return 0;
-        }
-        int len = A.length, wordLen = A[0].length(), res = 0;
-        boolean[] cut = new boolean[len];
-    search:
-        for (int j = 0; j < wordLen; j++) {
-            // 判断第 j 列是否应当保留
-            for (int i = 0; i < len - 1; i++) {
-                if (!cut[i] && A[i].charAt(j) > A[i + 1].charAt(j)) {
-                    res += 1;
-                    continue search;
+    public int minDeletionSize(String[] strs) {
+        int n = strs.length;
+        int m = strs[0].length();
+        boolean[] st = new boolean[n - 1];
+        int ans = 0;
+        for (int j = 0; j < m; ++j) {
+            boolean mustDel = false;
+            for (int i = 0; i < n - 1; ++i) {
+                if (!st[i] && strs[i].charAt(j) > strs[i + 1].charAt(j)) {
+                    mustDel = true;
+                    break;
                 }
             }
-            // 更新 cut 的信息
-            for (int i = 0; i < len - 1; i++) {
-                if (A[i].charAt(j) < A[i + 1].charAt(j)) {
-                    cut[i] = true;
+            if (mustDel) {
+                ++ans;
+            } else {
+                for (int i = 0; i < n - 1; ++i) {
+                    if (!st[i] && strs[i].charAt(j) < strs[i + 1].charAt(j)) {
+                        st[i] = true;
+                    }
                 }
             }
         }
-        return res;
+        return ans;
     }
-}
\ No newline at end of file
+}
diff --git a/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.py b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.py
new file mode 100644
index 0000000000000..22feb8c5201eb
--- /dev/null
+++ b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.py	
@@ -0,0 +1,19 @@
+class Solution:
+    def minDeletionSize(self, strs: List[str]) -> int:
+        n = len(strs)
+        m = len(strs[0])
+        st = [False] * (n - 1)
+        ans = 0
+        for j in range(m):
+            must_del = False
+            for i in range(n - 1):
+                if not st[i] and strs[i][j] > strs[i + 1][j]:
+                    must_del = True
+                    break
+            if must_del:
+                ans += 1
+            else:
+                for i in range(n - 1):
+                    if not st[i] and strs[i][j] < strs[i + 1][j]:
+                        st[i] = True
+        return ans
diff --git a/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.rs b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.rs
new file mode 100644
index 0000000000000..31e96b4e12b1f
--- /dev/null
+++ b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.rs	
@@ -0,0 +1,29 @@
+impl Solution {
+    pub fn min_deletion_size(strs: Vec) -> i32 {
+        let n = strs.len();
+        let m = strs[0].len();
+        let mut st = vec![false; n - 1];
+        let mut ans = 0;
+
+        for j in 0..m {
+            let mut must_del = false;
+            for i in 0..n - 1 {
+                if !st[i] && strs[i].as_bytes()[j] > strs[i + 1].as_bytes()[j] {
+                    must_del = true;
+                    break;
+                }
+            }
+            if must_del {
+                ans += 1;
+            } else {
+                for i in 0..n - 1 {
+                    if !st[i] && strs[i].as_bytes()[j] < strs[i + 1].as_bytes()[j] {
+                        st[i] = true;
+                    }
+                }
+            }
+        }
+
+        ans
+    }
+}
diff --git a/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.ts b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.ts
new file mode 100644
index 0000000000000..4eacf5a7dc301
--- /dev/null
+++ b/solution/0900-0999/0955.Delete Columns to Make Sorted II/Solution.ts	
@@ -0,0 +1,27 @@
+function minDeletionSize(strs: string[]): number {
+    const n = strs.length;
+    const m = strs[0].length;
+    const st: boolean[] = Array(n - 1).fill(false);
+    let ans = 0;
+
+    for (let j = 0; j < m; j++) {
+        let mustDel = false;
+        for (let i = 0; i < n - 1; i++) {
+            if (!st[i] && strs[i][j] > strs[i + 1][j]) {
+                mustDel = true;
+                break;
+            }
+        }
+        if (mustDel) {
+            ans++;
+        } else {
+            for (let i = 0; i < n - 1; i++) {
+                if (!st[i] && strs[i][j] < strs[i + 1][j]) {
+                    st[i] = true;
+                }
+            }
+        }
+    }
+
+    return ans;
+}