LeetCode 316. Remove Duplicate Letters(删除重复字母)

来源:互联网 发布:淘宝怎么把顾客拉黑 编辑:程序博客网 时间:2024/06/05 14:10

原题网址:https://leetcode.com/problems/remove-duplicate-letters/

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"

方法一:逐个字母找出。例如要找出第一个字母,首先找到最右边的一个点,使该点右边能够包含全部的字母,则第一个字母必在该点左边(包含该点),寻找方法是从该点向左搜寻,搜寻到一个字母表最靠前的、位置最靠左的字母,则为第一个字母。

public class Solution {    public String removeDuplicateLetters(String s) {        char[] sa = s.toCharArray();        int[] alphabet = new int[26];        int count = 0;        for(int i=0; i<sa.length; i++) {            if (alphabet[sa[i]-'a']==0) count ++;            alphabet[sa[i]-'a'] ++;        }        char[] removed = new char[count];        int left = 0;        int right = sa.length;        int c = 0;        Arrays.fill(alphabet, 0);        while (c<count) {            right --;            if (alphabet[sa[right]-'a']==0) c ++;            alphabet[sa[right]-'a'] ++;        }        for(int i=0; i<count; i++) {            char ch = sa[right];            int leftmost=right;            for(int j=right-1; j>=left; j--) {                if (sa[j] <= ch && alphabet[sa[j]-'a'] != 0) {                    ch = sa[j];                    leftmost = j;                }            }            alphabet[ch-'a'] = 0;            removed[i] = ch;            left = leftmost + 1;            while (right<sa.length-1 && alphabet[sa[right]-'a'] != 1) {                if (alphabet[sa[right]-'a'] > 1) alphabet[sa[right]-'a'] --;                right ++;            }        }        return new String(removed);    }}

另一种实现:

public class Solution {    public String removeDuplicateLetters(String s) {        int[] f = new int[26];        char[] sa = s.toCharArray();        int count = 0;        for(int i=sa.length-1; i>=0; i--) {            if (f[sa[i]-'a'] == 0) count ++;            f[sa[i]-'a'] ++;        }        char[] unique = new char[count];        Arrays.fill(unique, (char)0xff);        int from = 0, to = 0;        int pos = 0;        for(int i=0; i<count; i++) {            while (to<sa.length && (f[sa[to]-'a']!=1)) f[sa[to++]-'a']--;            for(int j=from; j<=to; j++) {                if (f[sa[j]-'a']>0 && sa[j] < unique[i]) {                    unique[i] = sa[j];                    pos = j;                }            }            while (pos+1<to) f[sa[--to]-'a']++;            f[unique[i]-'a'] = 0;            from = pos + 1;            to = from;        }        return new String(unique);    }}

又一个实现:

public class Solution {    public String removeDuplicateLetters(String s) {        if (s == null || s.length() == 0) return s;        char[] sa = s.toCharArray();        int[] f = new int[26];        int len = 0;        for(int i=0; i<sa.length; i++) {            if (f[sa[i]-'a'] ++ == 0) len ++;        }        char[] unique = new char[len];        int from = 0;        for(int i=0; i<unique.length; i++) {            int right = from;            int pos = -1;            while (right < sa.length && f[sa[right++]-'a']-- != 1);            for(int j=from; j<right; j++) {                if (f[sa[j]-'a'] >= 0 && (pos==-1 || sa[j]<sa[pos])) pos = j;            }            unique[i] = sa[pos];            for(int j=pos; j<right; j++) {                f[sa[j]-'a'] ++;            }            f[sa[pos]-'a'] = 0;            from = pos + 1;        }        return new String(unique);    }}

方法二:使用堆。

public class Solution {    public String removeDuplicateLetters(String s) {        char[] sa = s.toCharArray();        int[] f = new int[26];        int count = 0;        // 统计不同的字符个数        for(char ch : sa) {            if (f[ch - 'a']++ == 0) count++;        }        char[] result = new char[count];        PriorityQueue<Character> heap = new PriorityQueue<>();        int i = 0;        int from = 0, to = 0;        while (i < result.length) {            // 找到最大可能靠后的候选字符位置            while (to < sa.length) {                if (f[sa[to] - 'a'] > 0) {                    heap.offer(sa[to]);                    if (--f[sa[to++] - 'a'] == 0) break;                } else {                    to++;                }            }            char ch = (char)0;            do {                ch = heap.poll();                while (heap.remove(ch));                result[i++] = ch;                f[ch - 'a'] = 0;                // 该字符前面的字符已经作废,从堆中删除                while (sa[from++] != ch) {                    heap.remove(sa[from - 1]);                }            // 如果最大可能靠后的候选字符已经被选择,则终止            } while (ch != sa[to - 1]);        }        return new String(result);    }}

方法三:使用二叉搜索树。

public class Solution {    int size = 0;    int[] set = new int[26];    int[] tree = new int[26];    private void offer(int val) {        int i = 0, j = 25;        while (i <= j) {            int m = (i + j) >> 1;            if (m < val) {                i = m + 1;            } else {                tree[m] ++;                j = m - 1;            }        }        size ++;        set[val]++;    }    private boolean remove(int val) {        if (size == 0 || set[val] == 0) return false;        int i = 0, j = 25;        while (i <= j) {            int m = (i + j) >> 1;            if (m < val) {                i = m + 1;            } else {                tree[m] --;                j = m - 1;            }        }        size--;        set[val]--;        return true;    }    private int min() {        int i = 0, j = 25;        while (i <= j) {            int m = (i + j) >> 1;            if (tree[m] > 0) {                tree[m] --;                j = m - 1;            } else {                i = m + 1;            }        }        size--;        set[i]--;        return i;    }    public String removeDuplicateLetters(String s) {        char[] sa = s.toCharArray();        int[] f = new int[26];        int count = 0;        // 统计不同的字符个数        for(char ch : sa) {            if (f[ch - 'a']++ == 0) count++;        }        char[] result = new char[count];        int i = 0;        int from = 0, to = 0;        while (i < result.length) {            // 找到最大可能靠后的候选字符位置            while (to < sa.length) {                if (f[sa[to] - 'a'] > 0) {                    offer(sa[to] - 'a');                    if (--f[sa[to++] - 'a'] == 0) break;                 } else {                    to++;                }            }            char ch = (char)0;            do {                ch = (char)('a' + min());                while (remove(ch - 'a'));                result[i++] = ch;                f[ch - 'a'] = 0;                // 该字符前面的字符已经作废,从搜索树中删除                while (sa[from++] != ch) {                    remove(sa[from - 1] - 'a');                }            // 如果最大可能靠后的候选字符已经被选择,则终止            } while (from < to && ch != sa[to - 1]);        }        return new String(result);    }}


0 0
原创粉丝点击