955. Delete Columns to Make Sorted II

42 篇文章 0 订阅
18 篇文章 0 订阅

We are given an array A of N lowercase letter strings, all of the same length.

Now, we may choose any set of deletion indices, and for each string, we delete all the characters in those indices.

For example, if we have an array A = ["abcdef","uvwxyz"] and deletion indices {0, 2, 3}, then the final array after deletions is ["bef","vyz"].

Suppose we chose a set of deletion indices D such that after deletions, the final array has its elements in lexicographic order (A[0] <= A[1] <= A[2] ... <= A[A.length - 1]).

Return the minimum possible value of D.length.

 

Example 1:

Input: ["ca","bb","ac"]
Output: 1
Explanation: 
After deleting the first column, A = ["a", "b", "c"].
Now A is in lexicographic order (ie. A[0] <= A[1] <= A[2]).
We require at least 1 deletion since initially A was not in lexicographic order, so the answer is 1.

Example 2:

Input: ["xc","yb","za"]
Output: 0
Explanation: 
A is already in lexicographic order, so we don't need to delete anything.
Note that the rows of A are not necessarily in lexicographic order:
ie. it is NOT necessarily true that (A[0][0] <= A[0][1] <= ...)

Example 3:

Input: ["zyx","wvu","tsr"]
Output: 3
Explanation: 
We have to delete every column.

 

Note:

  1. 1 <= A.length <= 100
  2. 1 <= A[i].length <= 100

 

思路:一开始一直想着怎么删除哪些列,对于某一列来说,

1. 如果不是按照顺序排列的,那这一列可定就要删除掉,结果就是后面那部分的最小删除列数+1;

2. 如果都是unique的并且按照顺序排列,那说明后面的不需要删除了,直接返回前面那部分需要删除的最小列数;

3. 如果是按照顺序排列,但是不是都unique,那就需要分成很多group,每个group是重复字符所属的那些index,最后的结果是这些group的交集??

具体代码如下

from collections import defaultdict
class Solution(object):
    def minDeletionSize(self, A):
        """
        :type A: List[str]
        :rtype: int
        """
        def helper(a, idx):
            n=len(a[0])
            res=set()
            for i in range(idx, n):
                s = [t[i] for t in a]
                ss = sorted(s)
                if ''.join(ss)==''.join(s):
                    if len(set(s))==len(s):
                        return res
                    else:
                        d = defaultdict(list)
                        for j,v in enumerate(s):
                            d[v].append(j)
                        t = set()
                        for k in d:
                            if len(d[k])==1: continue
                            t = t|(helper(a[min(d[k]):max(d[k])+1],i+1))
                        res|=t
                        return res
                else:
                    res.add(i)
            return res
        
        return len(helper(A,0))

用这种方法提交是会WA的,因为不同group之间不是独立的,比如group A就靠着index为i的位置不需要在比后面的部分了,但是对于group B来说可能index为i的列是一定要删除的。而这个时候删除第i列,group A就需要重新计算最小删除的列数了。

所以分成group不行,不分又算不下去。

 

答案是:换个角度,不要想着删除哪些列,考虑最后保留哪些列。

比如遍历到index为i的列,前面保留了若干列,现在就只需要判断现在可不可以把第i列保存下来即可。

这样就避免了上面group的问题,因为每次判断都考虑了前面的所有字符

class Solution(object):
    def minDeletionSize(self, A):
        """
        :type A: List[str]
        :rtype: int
        """
        res=0
        remains = ['']*len(A)
        for i in range(len(A[0])):
            remains_tmp = [t+A[idx][i] for idx,t in enumerate(remains)]
            if ''.join(remains_tmp)==''.join(sorted(remains_tmp)):
                remains = remains_tmp
            else:
                res+=1
        return res

这其实是greedy算法

Intuition:
Solve it with a greed algorithme.

Initial N empty string.
For each column,
add the character to each row,
and check if all rows are still sorted.

If not, we have to delete this column.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值