web-dev-qa-db-ja.com

文字列内の最初の繰り返されていない文字を検索します

文字列に1回だけ表示される最初の文字を見つける最も簡単な方法は何ですか?

24
Thunderhashy

文字列全体を処理するまで、文字が繰り返されていないことを知ることはできないので、私の提案は次のようになります。

def first_non_repeated_character(string):
  chars = []
  repeated = []
  for character in string:
    if character in chars:
      chars.remove(character)
      repeated.append(character)
    else:
      if not character in repeated:
        chars.append(character)
  if len(chars):
    return chars[0]
  else:
    return False

編集:最初に投稿されたコードは悪かったが、この最新のスニペットはRyan'sComputer™で動作することが認定されています。

14
Ryan Prior

すべての文字を読むまで文字が繰り返されるかどうかわからないため、少なくともO(n)である必要があります。

したがって、文字を繰り返して、最初に表示したときに各文字をリストに追加し、表示した回数を個別にカウントすることができます(実際、カウントに重要な値は「0」のみです。 、「1」または「複数」)。

文字列の最後に到達したら、リスト内でカウントが1つだけの最初の文字を見つける必要があります。


Pythonのサンプルコード:

def first_non_repeated_character(s):
    counts = defaultdict(int)
    l = []
    for c in s:
        counts[c] += 1
        if counts[c] == 1:
            l.append(c)

    for c in l:
        if counts[c] == 1:
            return c

    return None

これはO(n)で実行されます。

32
Mark Byers

最小優先度キューなどのヒープベースのデータ構造を使用してみませんか。文字列から各文字を読み取るときに、文字列内の場所とこれまでの出現回数に基づいて優先順位を付けてキューに追加します。キューを変更して衝突時の優先度を追加し、キャラクターの優先度がそのキャラクターの出現回数の合計になるようにすることができます。ループの終わりに、キューの最初の要素は文字列の中で最も頻度の低い文字になり、カウント== 1の文字が複数ある場合、最初の要素はキューに追加された最初の一意の文字でした。

4
just_wes

これを行う別の楽しい方法があります。カウンターにはPython2.7または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("aaabbbcddd")
'c'
>>> first_non_repeated_character("aaaebbbcddd")
'e'
3
John La Rooy

多くの回答がO(n)を試みていますが、追跡に使用しているリスト/連想配列/セットへの挿入と削除の実際のコストを忘れています。

Charが1バイトであると想定できる場合は、charでインデックス付けされた単純な配列を使用し、その中にカウントを保持します。配列アクセスはO(1)が保証されているため、これは本当にO(n)であり、1を持つ最初の要素を見つけるための配列の最後のパスは定数時間です(配列には小さい、固定サイズ)。

文字が1バイトであると想定できない場合は、文字列を並べ替えてから、隣接する値をチェックするシングルパスを実行することをお勧めします。これは、ソートの場合はO(n log n)に、最終パスの場合はO(n))になります。したがって、実質的にはO(n log n)であり、O(n ^ 2よりも優れています) )また、実質的にスペースオーバーヘッドがありません。これは、O(n)を試行している多くの回答のも​​う1つの問題です。

3
Adrian McCarthy

以下は、文字列の最初の繰り返されない文字を見つけるRuby実装です。

def first_non_repeated_character(string)
  string1 = string.split('')
  string2 = string.split('')

  string1.each do |let1|
    counter = 0
    string2.each do |let2|
      if let1 == let2
        counter+=1
      end
    end
  if counter == 1 
    return let1
    break
  end
end
end

p first_non_repeated_character('dont doddle in the forest')

そして、これが同じスタイルの関数のJavaScript実装です。

var first_non_repeated_character = function (string) {
  var string1 = string.split('');
  var string2 = string.split('');

  var single_letters = [];

  for (var i = 0; i < string1.length; i++) {
    var count = 0;
    for (var x = 0; x < string2.length; x++) {
      if (string1[i] == string2[x]) {
        count++
      }
    }
    if (count == 1) {
      return string1[i];
    }
  }
}

console.log(first_non_repeated_character('dont doddle in the forest'));
console.log(first_non_repeated_character('how are you today really?'));

どちらの場合も、文字が文字列のどこにも一致しない場合、文字列で1回だけ発生することを知っているカウンターを使用したので、その発生をカウントします。

2
user1798670

カウンターにはPython2.7またはPython3.1が必要です

>>> from collections import Counter
>>> def first_non_repeated_character(s):
...     counts = Counter(s)
...     for c in s:
...         if counts[c]==1:
...             return c
...     return None
... 
>>> first_non_repeated_character("aaabbbcddd")
'c'
>>> first_non_repeated_character("aaaebbbcddd")
'e'
2
John La Rooy

以前に提案されたソリューションのリファクタリング(追加のリスト/メモリを使用する必要はありません)。これは文字列を2回超えます。したがって、これはO(n)元のソリューションとあまりにも似ています。

def first_non_repeated_character(s):
    counts = defaultdict(int)
    for c in s:
        counts[c] += 1
    for c in s:
        if counts[c] == 1:
            return c
    return None
2
Magge

これはCで行う必要があると思います。これはO(n)時間で動作し、挿入演算子と削除演算子の順序にあいまいさはありません。これはカウントソート(バケットソートの最も単純な形式、これ自体が基数ソートの単純な形式です)。

unsigned char find_first_unique(unsigned char *string)
{
    int chars[256];
    int i=0;
    memset(chars, 0, sizeof(chars));

    while (string[i++])
    {
        chars[string[i]]++;
    }

    i = 0;
    while (string[i++])
    {
        if (chars[string[i]] == 1) return string[i];
    }
    return 0;
}
2
Pete Fordham

他のJavaScriptソリューションはかなりcスタイルのソリューションであり、ここではよりJavaScriptスタイルのソリューションです。

var arr = string.split("");
var occurences = {};
var tmp;
var lowestindex = string.length+1;

arr.forEach( function(c){ 
  tmp = c;
  if( typeof occurences[tmp] == "undefined")
    occurences[tmp] = tmp;
  else 
    occurences[tmp] += tmp;
});


for(var p in occurences) {
  if(occurences[p].length == 1)
    lowestindex = Math.min(lowestindex, string.indexOf(p));
}

if(lowestindex > string.length)
  return null;

return string[lowestindex];

}
1
JonathanC
def first_non_repeated_character(string):
  chars = []
  repeated = []
  for character in string:
    if character in repeated:
        ... discard it.
    else if character in chars:
      chars.remove(character)
      repeated.append(character)
    else:
      if not character in repeated:
        chars.append(character)
  if len(chars):
    return chars[0]
  else:
    return False
1
Sachin Magdum

Rubyの場合:

(元のクレジット:Andrew A. Smith)

x = "a huge string in which some characters repeat"

def first_unique_character(s)
 s.each_char.detect { |c| s.count(c) == 1 }
end

first_unique_character(x)
=> "u"
1
rantler

_Array#detect_を使用せずにRubyで可能な解決策は次のとおりです( この回答 のように)。_Array#detect_を使用すると簡単すぎると思います。

_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
_

いくつかの簡単な例で機能するようです:

_fnr "abcdabcegghh"
# => "d"

fnr "abababababababaqababa"                                    
=> "q"
_

提案や訂正は大歓迎です!

0
bowsersenior

o(n)時間計算量のもう1つの解決策があります。

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
Stuck in Java

繰り返される文字が連続しているかどうかを気にしないPerl(バージョン> = 5.10)の実装は次のとおりです。

use strict;
use warnings;

foreach my $Word(@ARGV)
{
  my @distinct_chars;
  my %char_counts;

  my @chars=split(//,$Word);

  foreach (@chars)
  {
    Push @distinct_chars,$_ unless $_~~@distinct_chars;
    $char_counts{$_}++;
  }

  my $first_non_repeated="";

  foreach(@distinct_chars)
  {
    if($char_counts{$_}==1)
    {
      $first_non_repeated=$_;
      last;
    }
  }

  if(length($first_non_repeated))
  {
    print "For \"$Word\", the first non-repeated character is '$first_non_repeated'.\n";
  }
  else
  {
    print "All characters in \"$Word\" are repeated.\n";
  }
}

このコードをスクリプトに保存する(私はnon_repeated.pl)いくつかの入力で実行すると、次のようになります。

jmaney> Perl non_repeated.pl aabccd "a huge string in which some characters repeat" abcabc
For "aabccd", the first non-repeated character is 'b'.
For "a huge string in which some characters repeat", the first non-repeated character is 'u'.
All characters in "abcabc" are repeated.
0
user554546

次のソリューションは、Java 8として導入された新機能を使用して、文字列内の最初の一意の文字を見つけるエレガントな方法です。このソリューションは、最初にマップを作成するアプローチを使用します。各文字の出現回数をカウントし、このマップを使用して、1回だけ出現する最初の文字を検索します。これはO(N)時間で実行されます。

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
Jeff

「unique」と「repeated」の2つの文字列があります。初めて登場するすべてのキャラクターは、「ユニーク」に追加されます。 2回目に繰り返されると、「unique」から削除され、「repeated」に追加されます。このように、「unique」には常に一意の文字列があります。複雑さ大きなO(n)

public void firstUniqueChar(String str){
    String unique= "";
    String repeated = "";
    str = str.toLowerCase();
    for(int i=0; i<str.length();i++){
        char ch = str.charAt(i);
        if(!(repeated.contains(str.subSequence(i, i+1))))
            if(unique.contains(str.subSequence(i, i+1))){
                unique = unique.replaceAll(Character.toString(ch), "");
                repeated = repeated+ch;
            }
            else
                unique = unique+ch;
    }
    System.out.println(unique.charAt(0));
}
0
Swapnil Chilate

ここでは別のアプローチ。文字列内の各要素をスキャンし、各要素の繰り返しカウントを格納するカウント配列を作成します。次回は、配列の最初の要素から開始し、count = 1の要素の最初の出現を出力します

C code 
-----
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char t_c;
    char *t_p = argv[1] ;
    char count[128]={'\0'};
    char ch;

    for(t_c = *(argv[1]); t_c != '\0'; t_c = *(++t_p))
        count[t_c]++;
    t_p = argv[1];
    for(t_c = *t_p; t_c != '\0'; t_c = *(++t_p))
    {
        if(count[t_c] == 1)
        {
            printf("Element is %c\n",t_c);
            break;
        }
    }

return 0;    
} 

このコードを試してください:

    public static String findFirstUnique(String str)
    {
        String unique = "";

        foreach (char ch in str)
        {
            if (unique.Contains(ch)) unique=unique.Replace(ch.ToString(), "");
            else unique += ch.ToString();
        }
        return unique[0].ToString();
    }
0
Korey Hinton

これは別のアプローチです...文字の最初の出現のカウントとインデックスを格納する配列を持つことができます。配列を埋めた後、jstは配列をトラバースし、カウントが1のMINIMUMインデックスを見つけて、str [index]を返します。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <climits>
using namespace std;

#define No_of_chars 256

//store the count and the index where the char first appear
typedef struct countarray
{
    int count;
    int index;
}countarray;

//returns the count array
    countarray *getcountarray(char *str)
    {
        countarray *count;
        count=new countarray[No_of_chars];
        for(int i=0;i<No_of_chars;i++)
        {
            count[i].count=0;
            count[i].index=-1;
        }
        for(int i=0;*(str+i);i++)
        {
            (count[*(str+i)].count)++;
            if(count[*(str+i)].count==1) //if count==1 then update the index
                count[*(str+i)].index=i; 

        }
        return count;
    }

    char firstnonrepeatingchar(char *str)
    {
        countarray *array;
        array = getcountarray(str);
        int result = INT_MAX;
        for(int i=0;i<No_of_chars;i++)
        {
            if(array[i].count==1 && result > array[i].index)
                result = array[i].index;
        }
        delete[] (array);
        return (str[result]);
    }

    int main()
    {
        char str[] = "geeksforgeeks";
        cout<<"First non repeating character is "<<firstnonrepeatingchar(str)<<endl;        
        return 0;
    }
0
Vikash kumar

cでは、これはほぼ 画家のアルゴリズムShlemiel (完全にO(n!)ではありませんが0(n2)より大きい)です。

ただし、Oが非常に小さいため、適度なサイズの文字列の「より良い」アルゴリズムよりもパフォーマンスが高くなります。これにより、最初の非繰り返し文字列のlocationも簡単にわかります。

char FirstNonRepeatedChar(char * psz)
{
   for (int ii = 0; psz[ii] != 0; ++ii)
   {
      for (int jj = ii+1; ; ++jj)
      {
         // if we hit the end of string, then we found a non-repeat character.
         //
         if (psz[jj] == 0)
            return psz[ii]; // this character doesn't repeat

         // if we found a repeat character, we can stop looking.
         //
         if (psz[ii] == psz[jj])
            break; 
      }
   }

   return 0; // there were no non-repeating characters.
}

編集:このコードは、連続の繰り返し文字を意味しないことを前提としています。

0
John Knoeller

JavaScriptのこのスニペットコード

var string = "tooth";
var hash = [];
for(var i=0; j=string.length, i<j; i++){
    if(hash[string[i]] !== undefined){
        hash[string[i]] = hash[string[i]] + 1;
    }else{
        hash[string[i]] = 1;
    }
}

for(i=0; j=string.length, i<j; i++){
    if(hash[string[i]] === 1){
        console.info( string[i] );
        return false;
    }
}
// prints "h"
0
Raghava Kotekar

入力は= aabbcddeef出力は= c

char FindUniqueChar(char *a)
{
    int i=0;
    bool repeat=false;
    while(a[i] != '\0')
    {
      if (a[i] == a[i+1])
      {
        repeat = true;
      }
      else
      {
            if(!repeat)
            {
            cout<<a[i];
            return a[i];
            }
        repeat=false;
      }
      i++;
    }
    return a[i];
}
0
kriya

Mathematica でこれを書くかもしれません:

string = "conservationist deliberately treasures analytical";

Cases[Gather @ Characters @ string, {_}, 1, 1][[1]]
{"v"}
0
Mr.Wizard

私は答えを読み通しましたが、私のようなものは見当たりませんでした。この答えは非常に単純で速いと思います、私は間違っていますか?

def first_unique(s):
    repeated = []

    while s:
        if s[0] not in s[1:] and s[0] not in repeated:
            return s[0]
        else:
            repeated.append(s[0])
            s = s[1:]
    return None

テスト

(first_unique('abdcab') == 'd', first_unique('aabbccdad') == None, first_unique('') == None, first_unique('a') == 'a')
0
mac

質問:文字列の最初の一意の文字これは最も簡単な解決策です。

public class Test4 {
    public static void main(String[] args) {
        String a = "GiniGinaProtijayi";

        firstUniqCharindex(a);
    }

    public static void firstUniqCharindex(String a) {
        int[] count = new int[256];
        for (int i = 0; i < a.length(); i++) {
            count[a.charAt(i)]++;
        }
        int index = -1;
        for (int i = 0; i < a.length(); i++) {
            if (count[a.charAt(i)] == 1) {
                index = i;
                break;
            } // if
        }
        System.out.println(index);// output => 8
        System.out.println(a.charAt(index)); //output => P

    }// end1
}

IN Python:

def firstUniqChar(a):
  count = [0] * 256
  for i in a: count[ord(i)] += 1 
  element = ""
  for items in a:
      if(count[ord(items) ] == 1):
          element = items ;
          break
  return element


a = "GiniGinaProtijayi";
print(firstUniqChar(a)) # output is P

Java 8:

public class Test2 {
    public static void main(String[] args) {
        String a = "GiniGinaProtijayi";

        Map<Character, Long> map = a.chars()
                .mapToObj(
                        ch -> Character.valueOf((char) ch)

        ).collect(
                Collectors.groupingBy(
                        Function.identity(), 
                        LinkedHashMap::new,
                        Collectors.counting()));

        System.out.println("MAP => " + map);
        // {G=2, i=5, n=2, a=2, P=1, r=1, o=1, t=1, j=1, y=1}

        Character chh = map
                .entrySet()
                .stream()
                .filter(entry -> entry.getValue() == 1L)
                .map(entry -> entry.getKey())
                .findFirst()
                .get();
        System.out.println("First Non Repeating Character => " + chh);// P
    }// main

}
0
Soudipta Dutta

関数:

このc#関数はHashTable(Dictionary)を使用し、パフォーマンスO(2n)ワーストケースです。

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;
    }

例:

string aword = "TEETER";

Console.WriteLine(FirstNoRepeatingCharacter(aword)); //印刷:R

0
RolandoCC

次のコードはC#で、複雑さはnです。

using System;
using System.Linq;
using System.Text;

namespace SomethingDigital
{
    class FirstNonRepeatingChar
    {
        public static void Main()
        {
            String input = "geeksforgeeksandgeeksquizfor";
            char[] str = input.ToCharArray();

            bool[] b = new bool[256];
            String unique1 = "";
            String unique2 = "";

            foreach (char ch in str)
            {
                if (!unique1.Contains(ch))
                {
                    unique1 = unique1 + ch;
                    unique2 = unique2 + ch;
                }
                else
                {
                    unique2 = unique2.Replace(ch.ToString(), "");
                }
            }
            if (unique2 != "")
            {
                Console.WriteLine(unique2[0].ToString());
                Console.ReadLine();
            }
            else
            {
                Console.WriteLine("No non repeated string");
                Console.ReadLine();
            }
        }
    }
}
0
Kapil