web-dev-qa-db-ja.com

この関数の時間の複雑さはo(n)ですか?それ以上最適化できますか?

これは、文字列が一意の文字で構成されているかどうかを確認する非常に単純な関数です。これはO(n)時間の複雑さだと思います。1回ループし、1つのif条件があるためです。正しいですか?さらに最適化できる方法はありますか?

public class Program
 {
    public static void Main(string[] args)
    {
        DuplicateChars(args[0].ToLower());
    }

    public static bool DuplicateChars(string str)
    {
        bool[] charfound = new bool[26];
        int index = 0;

        for(int i = 0; i <= str.Length ; ++i)
        {
            index = (byte)(str[i]);
            //subtract by ascii value of small a 97.
            index -= 97;
            if(charfound[index])
                return true;
            else
                charfound[index] = true;
        }  

        return false;
    }
}
2

あなたのサンプルコードを考えると、次の仮定が真であると私は思います:

  • strには、_'a'_から_'z'_までの文字値のみが含まれます

それを考えると、最適化の機会がすぐにわかります。_str.Length_が_charfound.Length_より大きい場合、重複する文字があるため、関数の先頭にそのチェックを含めることができます。

_public class Program
{
    public static void Main(string[] args)
    {
        DuplicateChars(args[0].ToLower());
    }

    public static bool DuplicateChars(string str)
    {
        bool[] charfound = new bool[26];
        int index = 0;

        if(str.Length > charfound.Length) return true;

        for(int i = 0; i <= str.Length ; ++i)
        {
            index = (byte)(str[i]);
            //subtract by ascii value of small a 97.
            index -= 97;
            if(charfound[index])
                return true;
            else
                charfound[index] = true;
        }  

        return false;
    }
}
_

この変更後、最悪の場合の入力は_"abcdefghijklmnopqrstuvwxyz"_の順列で構成される文字列になります。これは、関数が最悪の場合O(1)であることを意味します。(Proofこれは読者のための演習として残されています。)

編集:コメントの@Pieter Bで指摘されているように、ToLower()への呼び出しをMainからif(str.Length > charfound.Length) return true;の直後に移動することをお勧めします。合計O(n)時間を費やしていません。

5
hoffmale

アルファベットのサイズに関する追加情報がある場合は、それを改善できます。

文字列にASCII文字のみを含めることができると仮定します。つまり、文字列には最大128個の一意の文字を含めることができます。128文字を超える文字列は重複した文字を持ちます。

つまり、文字列の長さが128以下の場合にのみDuplicateCharsを実行する必要があるということです。これにより、nに一定の上限が設定され、アルゴリズムがO(1)になります。

2