Find the first un-repeated character in a string

后端 未结 30 1272
猫巷女王i
猫巷女王i 2020-11-27 18:29

What is the quickest way to find the first character which only appears once in a string?

相关标签:
30条回答
  • 2020-11-27 19:15

    Here is another fun way to do it. Counter requires Python2.7 or Python3.1

    >>> from collections import Counter
    >>> def first_non_repeated_character(s):
    ...     return min((k for k,v in Counter(s).items() if v<2), key=s.index)
    ...
    >>> first_non_repeated_character("aaabbbcffffd")
    'c'
    >>> first_non_repeated_character("aaaebbbcffffd")
    'e'
    
    0 讨论(0)
  • Function:

    This c# function uses a HashTable (Dictionary) and have a performance O(2n) worstcase.

    private static string FirstNoRepeatingCharacter(string aword)
        {
            Dictionary<string, int> dic = new Dictionary<string, int>();            
    
            for (int i = 0; i < aword.Length; i++)
            {
                if (!dic.ContainsKey(aword.Substring(i, 1)))
                    dic.Add(aword.Substring(i, 1), 1);
                else
                    dic[aword.Substring(i, 1)]++;
            }
    
            foreach (var item in dic)
            {
                if (item.Value == 1) return item.Key;
            }
            return string.Empty;
        }
    

    Example:

    string aword = "TEETER";

    Console.WriteLine(FirstNoRepeatingCharacter(aword)); //print: R

    0 讨论(0)
  • 2020-11-27 19:15

    The following solution is an elegant way to find the first unique character within a string using the new features which have been introduced as part as Java 8. This solution uses the approach of first creating a map to count the number of occurrences of each character. It then uses this map to find the first character which occurs only once. This runs in O(N) time.

    import static java.util.stream.Collectors.counting;
    import static java.util.stream.Collectors.groupingBy;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    
    // Runs in O(N) time and uses lambdas and the stream API from Java 8
    //   Also, it is only three lines of code!
    private static String findFirstUniqueCharacterPerformantWithLambda(String inputString) {
      // convert the input string into a list of characters
      final List<String> inputCharacters = Arrays.asList(inputString.split(""));
    
      // first, construct a map to count the number of occurrences of each character
      final Map<Object, Long> characterCounts = inputCharacters
        .stream()
        .collect(groupingBy(s -> s, counting()));
    
      // then, find the first unique character by consulting the count map
      return inputCharacters
        .stream()
        .filter(s -> characterCounts.get(s) == 1)
        .findFirst()
        .orElse(null);
    }
    
    0 讨论(0)
  • 2020-11-27 19:16

    Here is one more solution with o(n) time complexity.

    public void findUnique(String string) {
        ArrayList<Character> uniqueList = new ArrayList<>();
        int[] chatArr = new int[128];
        for (int i = 0; i < string.length(); i++) {
            Character ch = string.charAt(i);
            if (chatArr[ch] != -1) {
                chatArr[ch] = -1;
                uniqueList.add(ch);
            } else {
                uniqueList.remove(ch);
            }
        }
        if (uniqueList.size() == 0) {
            System.out.println("No unique character found!");
        } else {
            System.out.println("First unique character is :" + uniqueList.get(0));
        }
    }
    
    0 讨论(0)
  • 2020-11-27 19:17

    Lots of answers are attempting O(n) but are forgetting the actual costs of inserting and removing from the lists/associative arrays/sets they're using to track.

    If you can assume that a char is a single byte, then you use a simple array indexed by the char and keep a count in it. This is truly O(n) because the array accesses are guaranteed O(1), and the final pass over the array to find the first element with 1 is constant time (because the array has a small, fixed size).

    If you can't assume that a char is a single byte, then I would propose sorting the string and then doing a single pass checking adjacent values. This would be O(n log n) for the sort plus O(n) for the final pass. So it's effectively O(n log n), which is better than O(n^2). Also, it has virtually no space overhead, which is another problem with many of the answers that are attempting O(n).

    0 讨论(0)
  • 2020-11-27 19:17

    Here's a possible solution in ruby without using Array#detect (as in this answer). Using Array#detect makes it too easy, I think.

    ALPHABET = %w(a b c d e f g h i j k l m n o p q r s t u v w x y z)
    
    def fnr(s)
      unseen_chars    = ALPHABET.dup
      seen_once_chars = []
      s.each_char do |c|
        if unseen_chars.include?(c)
          unseen_chars.delete(c)
          seen_once_chars << c
        elsif seen_once_chars.include?(c)
          seen_once_chars.delete(c)
        end
      end
    
      seen_once_chars.first
    end
    

    Seems to work for some simple examples:

    fnr "abcdabcegghh"
    # => "d"
    
    fnr "abababababababaqababa"                                    
    => "q"
    

    Suggestions and corrections are very much appreciated!

    0 讨论(0)
提交回复
热议问题