1

问题是在给定一些字符串 s 的情况下生成字典上最大的字符串。因此,目标是从 s 中找到字典顺序上最大的、唯一的(无重复)子字符串 s1。如果 s1 的字符数比 s2 多,或者如果长度相等,则我们说某个子序列 s1 大于另一个子序列 s2。

输入输出如下:

输入是:ba bab

输出是:巴

第二个输入是: nlhthgrfdnnlprjtecpdr t higjoqdejsfka soc tjijaoebql r gaiakfsbljm p ib k id j srtk g r d n q sk nb arp a bgokbsr fhm eklr le

第二个输出是:tsocrpkijgdqnbafhmle

这是我为我的 java 代码编写的,但我的代码在第二个测试用例中失败了。我也很难理解为什么第二个输出不是 tsrqponmlkjihgfedcba。有人可以提供修复甚至Java代码的建议吗?

我认为该算法必须比生成所有可能的唯一字符串、对它们进行排序并找到字典上最大的字符串更有效。

为了使问题更清楚,如果输入是 babab,那么所有可能的唯一组合将是 b、a、ba、ab。并且输出将是 ba,因为它是最长的并且在字典上大于 ab。

注意:这不是家庭作业。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


public class mostBeautiful {
final static int MAX = 1000000;
static String[] permute;
static void permutation(String prefix, String str, int counter) {
    int n = str.length();
    //System.out.println("n is: "+ n);
    if (n == 0) {
        permute[counter] = prefix;
    } else {
        for (int i = 0; i < n; i++) {
            //System.out.println("str is: "+ str);
            permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n), counter++);
        }
    }
}
public static void main(String[] args) throws IOException {
    BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    String s = bf.readLine();
    char[] unique = new char[26];
    int counter = 0;
    String answer = "";
    //System.out.println("s is: " + s);
    int ascii = 0;
    final int asciiAVal = 97;
    final int asciiZVal = 122;
    for (int i = 0; i < s.length(); i++) {
        ascii = (int)s.charAt(i);
        if (ascii < asciiAVal || ascii > asciiZVal) {
            continue;
        }
        char ch = s.charAt(i);
        unique[ch - 'a'] = ch;
    }
    String result = "";
    for (int j = 25; j >= 0; j--) {
        result += unique[j];
    }
    result = result.trim();
    System.out.println(result);
    int size = result.length() * (result.length() - 1);
    permute = new String[size];
    permutation("", result, counter);
    for (int i = 1; i < size; i++) {
        if (permute[i].compareTo(permute[i - 1]) > 0){
            answer = permute[i];
        }  else {
            answer = permute[i - 1];
        }

    }
    System.out.println("answer is: " + answer);
}

}

4

5 回答 5

2

在多方面思考了这个问题之后,我确定了一个分而治之的算法,可以得到正确的结果:

算法 - 伪代码

假设某个输入字符串 S 定义为两个子字符串 A + B 的串联,我们递归地计算字典序上最大的字符串为:

LexMax(S) = Merge(LexMax(A),LexMax(B))

在哪里

LexMax(S)
{
    if Length(S) = 1
        return S
    else
    {
        LMA = LexMax(S[0:Length/2])
        LMB = LexMax(S[Length/2:end])
        return Merge(LMA,LMB)
    }
}

Merge(A,B)
{
    Sa = A
    Sb = B

    for n = 0:Length(A)
    {
        if Sb contains A[n]
        {
            if A[n+1:end] contains character > A[n]
                Remove A[n] from Sa
            else
                Remove A[n] from Sb
        }
    }

    return Sa + Sb
}

Java 代码

快来了!

例子

给定一个输入字符串

cefcfdabbcfed

把它分成

cefcfda
bbcfed

假设函数有效,我们有:

LexMax("cefcfda") = "efcda"
LexMax("bbcfed") = "bcfed"

合并工作如下:

e: efcda bcfed

在两个子字符串中,在左侧子字符串中的 e 右侧找到更大的值,从左侧移除

f: fcda bcfed

在两个子字符串中,左侧子字符串中没有更大的值,从右侧删除

c: fcda bced

在两个子字符串中,在左子字符串中 c 的右侧找到更大的值,从左侧删除

d: fda bced

在两个子字符串中,左侧子字符串中没有更大的值,从右侧删除

a: fda bce

不在两个子字符串中,什么都不做

最后结果:

LexMax(cefcfdabbcfed) = fdabce
于 2012-07-10T00:32:43.660 回答
1

这不是一个直接的答案,但是此代码不符合您在上面讨论中解释的要求吗?

final String x = "saontehusanoethusnaoteusnaoetuh";
final SortedSet<Character> chars = 
   new TreeSet<Character>(Collections.reverseOrder());
for (char c : x.toCharArray()) chars.add(c);
System.out.println(chars);
于 2012-07-09T10:08:24.787 回答
1

字典顺序是使用单词中字母的出现按字母顺序显示单词的顺序。它也称为字典顺序或字母顺序。例如:-“Africa”小于“Bangladesh”,“He”比“他”小。

 public class LexicographicExample {  
      public static void main(String a[]) {  
           Scanner sc = new Scanner(System.in);  
           System.out.println("Enter the String:-");  
           String str = sc.nextLine();  
           System.out.println("Enter the length");  
           int count = sc.nextInt();  
           List<String> list = new ArrayList<String>();  
           for (int i = 0; i < str.length(); i = i + 1) {  
                if (str.length() - i >= count) {  
                     list.add(str.substring(i, count + i));  
                }  
           }  
           Collections.sort(list);  
           System.out.println("Smallest subString:-" + list.get(0));  
           System.out.println("Largest subString:-" + list.get(list.size() - 1));  
      }  
 }  

如需参考,请参阅此链接http://techno-terminal.blogspot.in/2015/09/java-program-to-find-lexicographically.html

于 2015-11-17T06:33:47.167 回答
0

“tsrqponmlkjihgfedcba”不是答案,因为它不是输入的子序列。子序列的定义要求子序列的字符以相同的顺序出现在原序列中。例如,“abc”是“apbqcr”的子序列,而“cba”不是。

至于解决方案,我认为一个简单的贪心算法就足够了。首先,必须了解输出的最大可能长度是输入中唯一符号的数量(例如 N)。由于任何比这更短的输出都不是最大的,因此它的长度必须正好为 N 个符号。该过程的其余部分很简单,并且时间复杂度最多为二次:必须遍历输入字符串,并在每一步中选择字典顺序最高的符号,以便字符串左侧的部分仍然包含所有“未使用”的符号。

例如,考虑一个字符串“bacb”。第一个符号可以是“a”或“b”,因为在这两种情况下,余数都包含其他两个字母。'b' 更大,所以我们选择它。现在对于“acb”,我们只能根据该条件选择“a”而不是“c”,因此我们最终以“bac”作为输出。

于 2012-07-09T14:04:26.643 回答
0
        import java.util.ArrayList;
        import java.util.HashMap;
        import java.util.Scanner;

        class aaa {
            public static void main(String args[]) throws Exception {
                Scanner scan = new Scanner(System.in);

                // int n = scan.nextInt();
                String s = scan.next();

                HashMap<Character, Node5> map = new HashMap<>();

                for (int i = 0; i < s.length(); i++) {
                    if (!map.containsKey(s.charAt(i))) {
                        Node5 node = new Node5();
                        node.nl.add(i);
                        node.li = i;
                        map.put(s.charAt(i), node);
                    } else {
                        Node5 rn = map.get(s.charAt(i));
                        rn.nl.add(i);
                        rn.li = i;
                        map.put(s.charAt(i), rn);
                    }
                }

                String s1 = "";
                int index = -1;
                for (int i = 25; i >= 0; i--) {
                    if (map.containsKey((char) (97 + i))) {
                        if (map.get((char) (97 + i)).li > index) {
                            for (int j = 0; j < map.get((char) (97 + i)).nl.size(); j++) {
                                if (map.get((char) (97 + i)).nl.get(j) > index) {
                                    s1 += (char) (97 + i);
                                    index = map.get((char) (97 + i)).nl.get(j);
                                }
                            }
                        }
                    }

                }
                System.out.println(s1);
                scan.close();
            }


        }

        class Node5 {
            int li;
            ArrayList<Integer> nl;

            public Node5() {
                this.nl = new ArrayList<>();
            }
        }
于 2017-07-17T13:54:17.027 回答