给定由 N 个小写字母字符串组成的数组 A,其中每个字符串长度相等。
选取一个删除索引序列,对于 A 中的每个字符串,删除对应每个索引处的字符。
比如,有 A = [“abcdef”, “uvwxyz”],删除索引序列 {0, 2, 3},删除后 A 为[“bef”, “vyz”]。
假设,我们选择了一组删除索引 D,那么在执行删除操作之后,最终得到的数组的元素是按 字典序(A[0] <= A[1] <= A[2] …
<= A[A.length - 1])排列的,然后请你返回 D.length 的最小可能值。示例 1:
输入:
[“ca”,“bb”,“ac”]
输出:1
解释: 删除第一列后,A = [“a”, “b”, “c”]。 现在 A中元素是按字典排列的 (即,A[0] <= A[1] <= A[2])。 我们至少需要进行 1 次删除,因为最初 A不是按字典序排列的,所以答案是 1。
示例 2:输入:
[“xc”,“yb”,“za”]
输出:0
解释: A 的列已经是按字典序排列了,所以我们不需要删除任何东西。 注意 A 的行不需要按字典序排列。 也就是说,A[0][0] <= A[0][1] <= … 不一定成立。 示例 3:输入:
[“zyx”,“wvu”,“tsr”]
输出:3
解释: 我们必须删掉每一列。提示:
1 <= A.length <= 100 1 <= A[i].length <= 100
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-columns-to-make-sorted-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
如果第一列是按从大到小排列的,并且相邻元素不相等,那么之后的都不用检查了;如果第一列是按从大到小排列,但是相邻元素存在相同,那么后面一列只用检查第一列相同的区域,区域内如果出现逆序对就要删除该列。那么就可以写递归了,往后传递需要价差的区域,第一列也可以归到相同的逻辑:
class Solution {
String[] AA;
int n;
int ret;
void rec(int col, List<int[]> equals) {
if(col == n || equals.isEmpty())
return;//边界条件
List<int[]> next = new ArrayList<>();//对下一个的问题 只有当这一列不删除的时候才有资格对下一列提问
for(int[] range : equals) {
int beg = range[0], end = range[1];
int i = beg + 1;
while(i <= end) {
if(AA[i].charAt(col) < AA[i - 1].charAt(col)) {
//出现逆序对 完蛋
++ret;
rec(col + 1, equals);
return;
} else if(AA[i].charAt(col) > AA[i - 1].charAt(col)) {
++i;
} else {
int [] r = new int[2];
r[0] = i - 1;
while(i <= end && AA[i].charAt(col) == AA[i - 1].charAt(col)) {
++i;
}
r[1] = i - 1;
next.add(r);
}
}
}
rec(col + 1, next);
}
public int minDeletionSize(String[] A) {
//如果用数据结构的迭代感觉麻烦干脆递归算了
//如果这招不行就抄答案
AA = A;
ret = 0;
if(A.length == 1)
return 0;
n = A[0].length();
List<int[]> equals = new ArrayList<>();
equals.add(new int[]{0, A.length - 1});
rec(0, equals);//检查第一列的从0到n-1个字符
return ret;
}
}
写的时候有点害怕,会不会出某一列没有逆序对但是删掉更好的情形,后来想想不可能。因为某一列不删掉和删掉相比,对下一列的要求肯定不会变得更严格,所以遇见可以保留的列无脑保留就好