leetcode - 316. Remove Duplicate Letters

算法系列博客之Greedy

Greedy 贪心算法是一种非常优美的算法,不过贪心算法本身的可行性很多时候会受到一些局限。但是一旦能够找到一种可行的贪心策略,问题的解决将会变得非常高效,因为通常情况下,贪心算法的复杂度是O(n)

本篇博客将运用这种思想来解决leetcode上316号问题


问题描述:

Given a string which contains only lowercase letters, remove duplicate letters so that every letter appear once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.

目的是要求出字典序最小的字符串,相同的字符保留且仅保留一个,且不改变字符相对顺序
为了保证相对顺序就必然需要扫描给定字符串,因而算法就应当尽量减小扫描的次数

以不同的视野,可以从以下两个角度出发
      ·   在给定字符串上按照某种规则去除字符
      ·   一个空字符串上按照某种规则增加字符
选择贪心算法,自然从给空字符串增加字符的角度更容易理解

      要得到字典序最小的字符串,很容易想到这样一种贪心的思想,即每次添加一个字符,使得在保证相同的字符都能保留的前提下这个字符尽量的小
那又要怎样来选择这个字符呢,每次都去扫描一遍给定字符串自然得不偿失
如果想要定义在扫描过程中,一个字符是否应该追加到结果中去,因为既需要保证相对顺序,又需要考虑字符尽量小且每个字符都需保留且仅保留一个,似乎太过于复杂

      换个角度,不妨这样,每次都尽量往结果中追加,这样便可解决相对顺序的问题和保留的问题
然后往后扫描,再根据后面的字符考虑是否需要将前面追加进去的字符删除,很方便的就解决了余下的尽量小的问题

首先获得26个字符每个字符出现的次数
于是对于线性扫描给定字符串的过程,我们得到如下的贪心策略:
无论如何将当前字符的次数减1
      ·   如果结果字符串中还没有这个字符,将其与前面追加到结果字符串尾部的字符进行比较:
          只要尾部字符对应的次数不为0并且字典序比这个字符大,即可将其删除,直到尾部字符不可删。这时,出于贪心将这个字符追加进去
      ·   如果结果字符串中已经有这个字符,则直接扫描下一个字符

_ _ _ 此贪心策略的可行性和正确性证明 _ _ _:
      ·   线性顺序扫描保证了字符的相对顺序
      ·   删除尾部字典序比当前扫描到的字符字典序大的字符,保证了得到的结果字符串是字典序最小的
      ·   删除尾部字符的必要条件是该字符次数判定为大于0,结果字符串没有此字符便添加的规则,以及对给定字符串的线性扫描保证了每个出现过的字符都会被保留且仅保留一次

python代码实现如下:

class Solution(object):
    def removeDuplicateLetters(self, s):
        res = "0"
        nums_alp = [0] * 26
        used = [False] * 26
        for c in s:
            nums_alp[ord(c)-ord('a')] += 1
        for c in s:
            posi_c = ord(c)-ord('a')
            nums_alp[posi_c] -= 1
            if not used[posi_c]:
                while c < res[-1] and nums_alp[ord(res[-1])-ord('a')]:
                    used[ord(res[-1])-ord('a')] = False
                    res = res[:-1]
                res += c
                used[posi_c] = True
        return res[1:]

时间复杂度分析,虽然这个算法看似循环里面还有一个循环,且内层循环的规模不确定
但,我们可以从另一个角度入手,结果字符串中放入的都是给定字符串里的字符,每个字符放入最多一次,删除也最多一次
因而,假设字符串规模为n,则时间复杂度为O(n)
空间复杂度分析,空间上,用到了两个长度为26的数组,抛开结果字符串的空间,则空间复杂度为O(1)

同众多贪心策略一样,这个贪心算法的实现在时间和空间上都是令人满意的

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值