leetcode :316 Remove Duplicate Letters : 贪心+递归搜索

316. Remove Duplicate Letters

My Submissions
Total Accepted: 11048  Total Submissions: 44956  Difficulty: Hard

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"









贪心+搜索:字符串全是字母,一共26个。每个字母都有它出现的位置,可能0个,可能多个。想要子串使得字母序最小且每个出现的字母只出现一次。那么:针对出现过的字母,从字典序按个安排位置,只要按照出现顺序都能安排下,就搜索到一个子串满足要求。

我的方法:使用数组保存26个字母出现的位置,每个字母出现的位置使用优先权队列保存,方便。。。(后来也发觉并没有什么卵用)。然后使用数组availItem表示字母是否可以被安排,使用数组maxIndex表示字母所能被安排的最大的位置(方便判断能否安排来减枝)。直到搜索到所有出现的字母都被安排即可。

public class Solution {
    public int findLine(Object[] objects,int lastIndex){
		
		int min=Integer.MAX_VALUE;
		for(int i=0;i<objects.length;i++){
			if((int)objects[i]>lastIndex&&(int)objects[i]<min)
				min=(int)objects[i];
		}
		return min;
	}
	public boolean linereach(int findline,int[] availItem,int[] maxIndex){
		for(int i=0;i<26;i++){
			if(availItem[i]==1&&maxIndex[i]<findline)
				return false;
		}
		return true;
	}
	public char[] search(ArrayList<PriorityQueue<Integer>> graph,int[] availItem,int[] maxIIndex,char[] reTemp,int x,int avialCount,int lastIndex){
		if(x>=avialCount)
			return reTemp;
		for(int i=0;i<26;i++){
			if(availItem[i]==1){
				int findline=findLine(graph.get(i).toArray(),lastIndex);
				if(linereach(findline,availItem,maxIIndex)){
					availItem[i]=0;
					reTemp[x]=(char) ('a'+i);
					char[] tt=search(graph, availItem, maxIIndex, reTemp, x+1, avialCount, findline);
					if(tt!=null)
						return tt;
					availItem[i]=1;
				}
			}
		}
		return null;
	}
	public String removeDuplicateLetters(String s) {
		ArrayList<PriorityQueue<Integer>> graph = new ArrayList<>();
		for (int i = 0; i < 26; i++)
			graph.add(new PriorityQueue<>());
		int[] availItem = new int[26];
		int[] maxIndex = new int[26];
		for (int i = 0; i < 26; i++)
			maxIndex[i] = availItem[i] = 0;
		int availCount = 0;
		for (int i = 0; i < s.length(); i++) {
			int itemNum = s.charAt(i) - 'a';
			graph.get(itemNum).add(i);
			if (availItem[itemNum] == 0) {
				availItem[itemNum] = 1;
				availCount++;
			}
			maxIndex[itemNum] = maxIndex[itemNum] < i ? i : maxIndex[itemNum];
		}
		char[] reTemp = new char[26];
		reTemp = search(graph, availItem, maxIndex, reTemp, 0, availCount,-1);
		return String.valueOf(reTemp,0,availCount);
	}
}

他们的代码真tm精炼。。。。代码的思路,本质上是一样的。

不过时间没我的快(10ms),嘻嘻~(他们的23ms)

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), ""));
    }
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值