如何查找给定字符串中的第一个字符,该字符只出现一次

时间:2013-02-17 15:06:18

标签: java string algorithm

这是一个面试问题。找到给定字符串中的第一个字符,该字符只出现一次(我想解决方案应该是Java)。

例如:

"babcbcd" -> 'a' // both 'a' and 'd' appear only once but 'a' appears before 'd'

琐碎的解决方案是

  • 构建地图(例如HashMap):char - >字符串中出现的次数;
  • 扫描字符串并测试地图的字符串字符,直到字符的为1.

有意义吗?什么是最好的地图实施?有没有更好,更有效的解决方案?

8 个答案:

答案 0 :(得分:3)

在Java中,您可以使用LinkedHashMap<Character,Integer>来计算每个字符在字符串中出现的次数。由于LinkedHashMap保留了插入顺序,因此您可以迭代其条目以查找恰好出现一次的第一个字符。

在合理的假设下,这将给出O(n)解决方案。

答案 1 :(得分:3)

这是Haskell中的一个版本。

import Data.List (elemIndices)
firstSingle str = take 1 [a | a <- str, length (elemIndices a str) == 1]

* Main Data.List&gt; firstSingle“babcbcd”
“一”

答案 2 :(得分:2)

如果我正在面试,我希望(尽管不一定期待)这样的事情:

def string = 'babcbcd'
def singles = string.toList().groupBy{ it }.findAll{ it.value.size() == 1 }.collect{ it.key }
println "First char that appears once: " + string.find{ singles.contains it }

关键是中间线。它将字符串作为字符列表groups the list逐个字符,因此您可以过滤掉一次不会发生的任何事情,最后生成一次出现的字符列表。然后我们只搜索字符串中该列表中的第一个字符。

这是Groovy,因为在Java中不可能优雅。也许一旦JDK 8终于成功......

更新:更简洁的版本,受@groovy's Haskell solution的启发。我现在几乎因为我的第一个人的笨拙而感到尴尬:)。

def firstUnique(seq) { seq.findAll{ seq.count(it) == 1 }.first() }

答案 3 :(得分:1)

您可以在原始字符串的一次传递中执行此操作:创建链接的哈希映射,存储您到目前为止找到的字符的计数。然后浏览地图条目(它将按插入顺序,因为它是一个链接的地图),当你看到一个计数时停止。

答案 4 :(得分:1)

你已经找到了一个很好的解决方案,但如果你想我建议采用不同的方法:

final String abc = "abcdefg....z";
boolean scanned[] = new boolean[abc.lenght()];
//set all to false ...
for(int i = 0; i<yourString.lenght(); i++){
    char c = yourString.charAt(i);
    if(!scanned[abc.indexOf(c)]){
        for(int j=i+1; j<yourString.lenght(); j++)
            if(yourString.charAt(i) == c){ // founded another
                scanned[abc.indexOf(c)] = true;
                break;
            }
        if(!scanned[abc.indexOf(c)])
            return c;
    }
}

答案 5 :(得分:1)

所有上述解决方案都需要O(n)内存。为了在O(1)内存中执行它,您可以为所有字符运行for循环(在ASCII中有128个)并计算出现次数和第一个外观然后找到fisrt非重复的char。时间复杂度O(128 | s |)。

int min=Integer.MAX_VALUE;
char ans=' '; //any initialization 
for ( i=0; i<128;i++){
    int count=0,first=-1;
    for(j=0;j<s.length();j++){
         if(s.charAt(j)==(char)(i)) count++;
         if(count==1) first=j;
         if(count>1) break;
    }
    if(count==1 && min>first){
         first=min;ans=s.charAt(first);
    }
}
if(min!=Integer.MAX_VALUE) System.out.println(ans);
else System.out.println("No such char found");

答案 6 :(得分:1)

假设String仅由a-z字符组成,您可以使用队列来查看到目前为止看到的字符并保持计数。

public static String findFirstLetterThatAppearsOnceInString(String str) {
    int[] seenCount = new int[26];
    int[] queue = new int[26];
    int queueSize = 0;
    for (char c : str.toCharArray()) { // Iterate over the input characters
        int i = c-'a';
        if (seenCount[i]<2) {
            seenCount[i]++;
            // If seen for the first time, store it in queue
            if (seenCount[i]==1) queue[queueSize++]=i;
        }
    }
    for (int qi=0;qi<queueSize;qi++) if (seenCount[queue[qi]]==1) return (char)(queue[qi]+'a')+"";
    return null;
}

答案 7 :(得分:1)

简单的非地图解决方案,假设没有unicode:

public String firstLonelyChar(String input)
{
    while(input.length() > 0)
    {
        int curLength = input.length();
        String first = String.valueOf(input.charAt(0));
        input = input.replaceAll(first, "");
        if(input.length() == curLength - 1)
            return first;
    }
    return null;
}