316-Remove Duplicate Letters

Description:
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.


Example:

Given "bcabc"
Return "abc"

Given "cbacdcbc"
Return "acdb"

问题描述:
给定一个只包含小写字母的字符串,删除重复元素,使得每个字符出现有且仅有一次。需要确保得到的结果为可能结果中字典序最小的那个。


问题分析:
解法1,递归
每一次递归,先获取当前字符串所有字符的出现次数,迭代当前字符串,找出最小字符,注意当任一字符最右位置为i时需终止迭代,删除最小字符左边的字符串,右边的字符串中的最小字符替换为空,继续处理剩下的字符串

解法2,迭代
与递归的思路类似


解法1(递归):

public class Solution {
    public String removeDuplicateLetters(String s) {
        int[] cnt = new int[26];
        int pos = 0; // the position for the smallest s[i]
        for (int i = 0; i < s.length(); i++) cnt[s.charAt(i) - 'a']++;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) < s.charAt(pos)) pos = i;
            //注意这里
            if (--cnt[s.charAt(i) - 'a'] == 0) break;
        }
        //注意,最小字符的右边的字符串将最小字符替换为空
        return s.length() == 0 ? "" : s.charAt(pos) + removeDuplicateLetters(s.substring(pos + 1).replaceAll("" + s.charAt(pos), ""));
    }
}

解法2(迭代):

/*
思路与递归相似
维护了lastPosMap,保存每个字符的最右下标,每次从[begin, end]找最小字符,end即为最小的最
右下标,注意,若最小字符为当前最右下标,需要更新end
*/
public class Solution {
    public String removeDuplicateLetters(String s) {
        if (s == null || s.length() <= 1) return s;

        Map lastPosMap = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            lastPosMap.put(s.charAt(i), i);
        }

        char[] result = new char[lastPosMap.size()];
        int begin = 0, end = findMinLastPos(lastPosMap);

        for (int i = 0; i < result.length; i++) {
            char minChar = 'z' + 1;
            for (int k = begin; k <= end; k++) {
                //注意这里对map的判断,因为删除不是删除字符串中的字符,而是删除map中的元素
                if (lastPosMap.containsKey(s.charAt(k)) && s.charAt(k) < minChar) {
                    minChar = s.charAt(k);
                    begin = k + 1;
                }
            }

            result[i] = minChar;
            if (i == result.length - 1) break;
            //注意这里,是将map中的元素删除
            lastPosMap.remove(minChar);
            //若最小字符与当前最右下标对应字符相同,那么需要更新end
            if (s.charAt(end) == minChar) end = findMinLastPos(lastPosMap);
        }

        return new String(result);
    }

    private int findMinLastPos(Map lastPosMap) {
        if (lastPosMap == null || lastPosMap.isEmpty()) return -1;
        int minLastPos = Integer.MAX_VALUE;
        for (int lastPos : lastPosMap.values()) {
             minLastPos = Math.min(minLastPos, lastPos);
        }
        return minLastPos;
    }

}

你可能感兴趣的:(算法与数据结构,leetcode全解)