```
class Solution(object):
def removeDuplicateLetters(self, s):
indexes={}
for i in xrange(len(s)-1,-1,-1):
if s[i] in indexes:
indexes[s[i]].append(i)
else:
indexes[s[i]]=[i]
cList=sorted(indexes.keys())
result=''
while len(result)<len(indexes):
bottom=min([indexes[c][0] for c in cList])
candidate=0
while indexes[cList[candidate]][-1]>bottom:
candidate+=1
result+=cList[candidate]
cList=cList[:candidate]+cList[candidate+1:]
for c in cList:
while indexes[c][-1]<indexes[result[-1]][-1]:
indexes[c].pop()
return result
```

Here is the version with annotation:

```
class Solution(object):
def removeDuplicateLetters(self, s):
"""
:type s: str
:rtype: str
"""
indexes={}
#construct a dict, to store a list of indexes for each letter.
for i in xrange(len(s)-1,-1,-1):
if s[i] in indexes:
indexes[s[i]].append(i)
else:
indexes[s[i]]=[i]
# make a list of letters in this string, sorted.
cList=sorted(indexes.keys())
result=''
# construct the result string until all letters are included
while len(result)<len(indexes):
# bottom is the boundary of the range to pick a letter. The definition of bottom
# is the last point beyound (and including itself) which there is at least one instance of
# each letter. Obviously, if we take the indexes of the last instance of each letter, then
# bottom is the min of these indexes.
# it is trivial to get the last instances since they are just the first element of each list
# in the indexes dict
bottom=min([indexes[c][0] for c in cList])
# obviously clearly, for the first element, we will have to pick before or at bottom
# otherwise, we will not be able to include all letters. And, in this [0, bottom] range,
# we will prefer to pick the smallest letter that's available.
# we use candidate to reach into cList, and since cList is sorted, we just need to find
# the first element in cList that has an instance before bottom. Conveniently, we
# just need to check the [-1] instance for each letter in cList, since that's the smallest
# index.
candidate=0
while indexes[cList[candidate]][-1]>bottom:
candidate+=1
# once candidate is found, append it to result
result+=cList[candidate]
# cut the candidate out of cList, we are not going to search this again in the furture.
cList=cList[:candidate]+cList[candidate+1:]
# all future candidates will be generated only after the current candidate index,
# so, pop all the earlier instances of all unused letters from indexes lists.
for c in cList:
while indexes[c][-1]<indexes[result[-1]][-1]:
indexes[c].pop()
#start again in the new range, and repeat the process for finding the first letter
return result
```