使用另一个排序顺序字符串对字符串排序

时间:2011-08-05 13:53:17

标签: string sorting

我在面试问题中看到了这一点, 给定排序顺序字符串,系统会要求您根据给定的排序顺序字符串对输入字符串进行排序   例如,如果排序顺序字符串是dfbcae   输入字符串为abcdeeabc   输出应为dbbccaaee

关于如何以有效的方式做到这一点的任何想法?

9 个答案:

答案 0 :(得分:6)

Counting Sort选项非常酷,当要排序的字符串与排序顺序字符串相比较长时,它很快。

  • 创建一个数组,其中每个索引对应于字母表中的字母,这是计数数组
  • 对于排序目标中的每个字母,递增计数数组中与该字母对应的索引
  • 表示排序顺序字符串中的每个字母
    • 将该字母添加到输出字符串的末尾,数次等于计数数组中的计数

算法复杂度为O(n),其中n是要排序的字符串的长度。正如维基百科文章所解释的那样,我们能够超越基于标准比较的排序的下限,因为这不是基于比较的排序。

这是一些伪代码。

char[26] countArray;
foreach(char c in sortTarget)
{
    countArray[c - 'a']++;
}

int head = 0;
foreach(char c in sortOrder)
{
    while(countArray[c - 'a'] > 0)
    {
        sortTarget[head] = c;
        head++;
        countArray[c - 'a']--;
    }
}

注意:此实现要求两个字符串仅包含小写字符。

答案 1 :(得分:3)

这是一个易于理解的算法,具有不错的算法复杂性。

对于排序顺序字符串

中的每个字符
  • 扫描要排序的字符串,从第一个非有序字符开始(您可以使用索引或指针跟踪此字符)
    • 当您发现指定字符的出现时,将其与第一个无序字符交换
    • 增加第一个无序字符的索引

这是O(n*m),其中n是要排序的字符串的长度,m是排序顺序字符串的长度。我们能够击败基于比较的排序的下限,因为该算法并不真正使用比较。像Counting Sort一样,它依赖于你有一个预定义的有限外部排序集。

这是一些伪代码:

int head = 0;
foreach(char c in sortOrder)
{
    for(int i = head; i < sortTarget.length; i++)
    {
        if(sortTarget[i] == c)
        {
             // swap i with head
             char temp = sortTarget[head];
             sortTarget[head] = sortTarget[i];
             sortTarget[i] = temp;

             head++;
        }
    }
}

答案 2 :(得分:0)

使用二分搜索查找不同字母之间的所有“分割点”,然后直接使用每个分段的长度。这将比天真的计数排序渐近更快,但实现起来会更难:

  • 使用大小为26 * 2的数组存储每个字母的开头和结尾;

  • 检查中间元素,看它是否与剩下的元素不同。如果是这样,那么这是中间元素的开始,并且在它之前的元素结束;

  • 丢弃具有相同开头和结尾的片段(如果有的话),递归地应用此算法。

由于最多有25个“分裂”,因此您不必搜索超过25个segemnts,并且对于每个分段,它都是O(logn)。由于这是constant * O(logn),因此算法为O(nlogn)。

当然,使用计数排序会更容易实现:

  • 使用大小为26的数组来记录不同字母的数量;

  • 扫描输入字符串;

  • 以给定的排序顺序输出字符串。

这是O(n),n是字符串的长度。

答案 3 :(得分:0)

在Python中,您只需创建一个索引并在比较表达式中使用它:

order = 'dfbcae'
input = 'abcdeeabc'

index = dict([ (y,x) for (x,y) in enumerate(order) ])
output = sorted(input, cmp=lambda x,y: index[x] - index[y])

print 'input=',''.join(input)
print 'output=',''.join(output)

给出了这个输出:

input= abcdeeabc
output= dbbccaaee

答案 4 :(得分:0)

面试问题通常与思考过程有关,通常不太关心语言功能,但无论如何我无法抗拒发布VB.Net 4.0版本。

“高效”可能意味着两件事。第一个是“什么是使计算机执行任务的最快方法”,第二个是“我们可以完成任务的最快速度”。它们可能听起来相同,但第一个可能意味着微优化,如int vs short,运行计时器来比较执行时间,并花费一周时间从算法中每毫秒调整一次。第二个定义是关于创建执行任务的代码需要多少人工时间(希望在合理的时间内)。如果代码A的运行速度比代码B快20倍,但代码B花费了1/20的时间来编写,具体取决于计时器的粒度(1ms vs 20ms,1周vs 20周),每个版本都可以被视为“高效”

    Dim input = "abcdeeabc"
    Dim sort = "dfbcae"

    Dim SortChars = sort.ToList()
    Dim output = New String((From c In input.ToList() Select c Order By SortChars.IndexOf(c)).ToArray())
    Trace.WriteLine(output)

答案 5 :(得分:0)

以下是我对问题的解决方案

import java.util.*;
import java.io.*;

class SortString
{
public static void main(String arg[])throws IOException
{
    BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    // System.out.println("Enter 1st String :");
    // System.out.println("Enter 1st String :");
    // String s1=br.readLine();
    // System.out.println("Enter 2nd String :");
    // String s2=br.readLine();
    String s1="tracctor";
    String s2="car";
    String com="";
    String uncom="";
    for(int i=0;i<s2.length();i++)
    {
        if(s1.contains(""+s2.charAt(i)))
        {
                com=com+s2.charAt(i);

        }
    }
    System.out.println("Com :"+com);
    for(int i=0;i<s1.length();i++)
        if(!com.contains(""+s1.charAt(i)))
        uncom=uncom+s1.charAt(i);

    System.out.println("Uncom "+uncom);
    System.out.println("Combined "+(com+uncom));
    HashMap<String,Integer> h1=new HashMap<String,Integer>();

    for(int i=0;i<s1.length();i++)
    {
        String m=""+s1.charAt(i);

        if(h1.containsKey(m))
        {
            int val=(int)h1.get(m);
            val=val+1;
            h1.put(m,val);
        }
        else
        {
            h1.put(m,new Integer(1));

        }
    }
    StringBuilder x=new StringBuilder();
    for(int i=0;i<com.length();i++)
    {
        if(h1.containsKey(""+com.charAt(i)))
        {
            int count=(int)h1.get(""+com.charAt(i));
            while(count!=0)
            {x.append(""+com.charAt(i));count--;}
        }
    }
    x.append(uncom);
    System.out.println("Sort "+x);

}

}

答案 6 :(得分:0)

这是我的版本,它是O(n)及时。我可以使用一个常量大小的char数组,而不是unordered_map。我...,E。假设输入字符串包含所有ASCII小字符,char char_count[256](并且已完成++char_count[ch - 'a'])。

string SortOrder(const string& input, const string& sort_order) {
  unordered_map<char, int> char_count;
  for (auto ch : input) {
    ++char_count[ch];
  }
  string res = "";
  for (auto ch : sort_order) {
    unordered_map<char, int>::iterator it = char_count.find(ch);
    if (it != char_count.end()) {
      string s(it->second, it->first);
      res += s;
    }
  }
  return res;
}

答案 7 :(得分:0)

    private static String sort(String target, String reference) {
    final Map<Character, Integer> referencesMap = new HashMap<Character, Integer>();

    for (int i = 0; i < reference.length(); i++) {
        char key = reference.charAt(i);
        if (!referencesMap.containsKey(key)) {
            referencesMap.put(key, i);
        }
    }

    List<Character> chars = new ArrayList<Character>(target.length());
    for (int i = 0; i < target.length(); i++) {
        chars.add(target.charAt(i));
    }

    Collections.sort(chars, new Comparator<Character>() {
        @Override
        public int compare(Character o1, Character o2) {
            return referencesMap.get(o1).compareTo(referencesMap.get(o2));
        }
    });

    StringBuilder sb = new StringBuilder();
    for (Character c : chars) {
        sb.append(c);
    }

    return sb.toString();
}

答案 8 :(得分:0)

在C#中,我只使用IComparer接口并将其保留给Array.Sort

{{1}}