https://leetcode.com/problems/remove-duplicate-letters/

参考
http://www.hrwhisper.me/leetcode-remove-duplicate-letters/
https://leetcode.com/discuss/73777/easy-to-understand-iterative-java-solution
http://www.bubuko.com/infodetail-1249912.html
http://bookshadow.com/weblog/2015/12/09/leetcode-remove-duplicate-letters/

总体思路:找每个字符出现的最后的位置last_pos,然后按照key = last_pos进行排序。从第一个区间里找到最小的字母,其对应的index为k,这个时候我们remove掉这个最小字母在OrderDict里的元素,然后将start = k + 1, 然后从k+1开始搜索,end始终为OrderDict的第一个元素,一直到OrderDict为空。

找每个字符出现的最后的位置, 取其中最小的作为end。求得end对应的字母X之后,其余字母以及X,要不就在end之前重复,要不就不重复,其对应的index是唯一的index。

这里注意求last_pos的trick

last_pos = collections.defaultdict(int)
for i, c in enumerate(s):
    last_pos[c] = i

自己重写code

未用orderdict,用tuple list。注意上面的思路

class Solution(object):
    def removeDuplicateLetters(self, s):
        """
        :type s: str
        :rtype: str
        """
        if len(s) == 0: return ''
        idx_dict = {}
        for i in xrange(len(s)):
            idx_dict[s[i]] = i
        alist = []
        for k,v in idx_dict.items():
            alist.append((k,v))#用tuple list,记录(letter, last_index)
        alist.sort(key = lambda x : x[1])
        start,i = 0,0
        ans = ''
        while i < len(s):

            if len(alist) > 0:
                (letter,idx) = alist[0]
                min_letter = 'z'
                while i <= idx:
                    if s[i] < min_letter and (s[i], idx_dict[s[i]]) in alist:#这里要s[i]在alist里面
                        min_letter = s[i]
                        start = i + 1
                    i += 1

                i = start#再从start这里开始搜,搜到alist第一个元素的idx
                ans += min_letter

                alist.remove((min_letter, idx_dict[min_letter]))
            else:
                break
        return ans

按照ref里的,用orderdict实现如下

class Solution(object):
    def removeDuplicateLetters(self, s):
        """
        :type s: str
        :rtype: str
        """
        if len(s) == 0: return ''
        idx_dict = {}
        for i in xrange(len(s)):
            idx_dict[s[i]] = i

        idx_dict = collections.OrderedDict(sorted(idx_dict.items(), key = lambda x:x[1]))#这里不要忘记.items()
        start, i = 0, 0
        ans = ''
        while i < len(s):
            if len(idx_dict) > 0:
                end = idx_dict.items()[0][1]#注意不是idx_dict.items[0][1], 要加括号
                min_letter = 'z'
                while i <= end:#注意这里不要少了等号
                    if s[i] < min_letter and s[i] in idx_dict:
                        min_letter = s[i]
                        start = i + 1
                    i += 1
                i = start#下一次从这个start开始
                ans += min_letter
                del idx_dict[min_letter]
            else:
                break
        return ans