题目
给定一个字符串str(只包含小写字母),返回字典序最小的且包含原字符串中所有的不同字符的子序列。
example:
输入:cdbdbbdbad
输出:cbad
输入:cbbaadbabc
输出:adbc
解题思路
逆向思考,将输入的字符串逆向进行读取,如果当前字符没有遇到过,将字符加入子序列,并记录在输入的字符串中的位置。否则比较当前字符跟子序列的第一个字符的顺序,如果当前字符字典序较小,将子序列中的当前字符去掉,并将当前字符作为子序列的第一个字符,如:
子序列:get;当前字符:z;更新后子序列为:zget
子序列:get;当前字符:e;更新后的子序列为:egt
程序实现
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String strSquence=in.nextLine();
System.out.println(getSubStrSquence(strSquence));
}
public static String getSubStrSquence(String strSquence){
char[] subStr=strSquence.toCharArray();
boolean[] Mark=new boolean[subStr.length];//如果子序列中存在subStr[i],那么Mark[i]=true;
int[] letter=new int[26];//字符在subStr中的位置
for(int i=0;i<26;i++)
letter[i]=-1;
char startChar=(char)('a'-1);
for(int i=subStr.length-1;i>=0;i--){
int loca=subStr[i]-'a';
if(i==subStr.length-1||letter[loca]==-1){
letter[loca]=i;
startChar=subStr[i];
Mark[i]=true;
}else{
int lastLoca=startChar-'a';
if(lastLoca>loca){
Mark[letter[loca]]=false;
letter[loca]=i;
Mark[i]=true;
startChar=subStr[i];
}
}
}
//另一种输出子序列的方法为对Letter中的出现顺序进行排序,输入字符串较长时,这种方法比较快
StringBuilder subStrSquence=new StringBuilder("");
for(int i=0;i<subStr.length;i++){
if(Mark[i]){
subStrSquence.append(subStr[i]);
}
}
return subStrSquence.toString();
}
}
复杂度分析
时间复杂度:O(n)
空间复杂度:O(n)