0

確率に基づいてランダムな文字を生成するのに問題があります。

たとえば、文字J、K、Q、Y、Zは、それぞれ1/96の確率で発生します。同様のプロセス(より高い確率で)が他の文字にも使用されます。

誰かがこれを行う方法を教えてもらえますか?

具体的に編集する:確率の分数に基づいてランダムな文字の文字を返す「getRandomLetter」というメソッドを作成しています。

4

5 に答える 5

3

特定の確率を持つ要素の離散セットから選択する一般的な方法は、ランダムな浮動小数点数を選択し、それがどの範囲にあるかを調べることです。例を挙げて説明します。確率がそれぞれ 0.255、0.407、0.338 の 3 つの文字 A、B、C から選択するとします。0 から 1 の間の乱数を計算します。

double r = Math.random();

まず、0 から 0.255 の範囲と比較します。

if (r < 0.255) {
    return 'A';
}

次に、0.255 から (0.255 + 0.407) の範囲に:

else if (r < 0.662) {
    return 'B';
}

どちらでもない場合は、次のようにする必要があります'C'

else {
    return 'C';
}

ifアルファベットの 26 文字すべてでこれを行う場合、 -elseステートメントの 26 ケースすべてを書き出すのは面倒です。事前にできることは、文字の配列とそれぞれの確率を準備することです。

char[] chars = {'A', 'B', 'C', ...};
double[] probabilities = {0.01, 0.02, 0.05, ...};

そして、次ifのようなループを使用して、そのすべてを自動化できます。

double r = Math.random();
double cdf = 0.0;
for (int i = 0; i < chars.length; i++) {
    cdf += probabilities[i]
    if (r < cdf) {
        return chars[i];
    }
}
return chars[chars.length - 1];

あなたの場合、すべての確率が 1/96 の倍数である場合、浮動小数点数の代わりに 96 未満のランダムな整数を選択して同じことを行うことができます。ints の代わりにdoubles を使用し、 の代わりに を使用rnd.nextInt(96)して 0 から 95 までの整数を選択しますMath.random()。また、probabilities配列には実際の確率の 96 倍が含まれます。

char[] chars = {'A', 'B', 'C', ...};
int[] probabilities = {5, 2, 4, ...}; // needs to sum to 96

// later...

int r = rnd.nextInt(96);
int cdf = 0;
for (int i = 0; i < chars.length; i++) {
    cdf += probabilities[i]
    if (r < cdf) {
        return chars[i];
    }
}
return chars[chars.length - 1];

ここで、バッグからスクラブル タイルを引き出すようなことをしている場合、それは置き換えのないサンプリング プロセスであるため、よりトリッキーになります。つまり、ドローするたびに確率が変化します。その場合のより良い方法は、実際にコレクションを使用してバッグをシミュレートし、その文字があるタイルごとに文字のコピーを 1 つ追加することだと思います。chars同じ配列とprobabilities前の配列を使用して、ループでこれを行うことができます。

char[] chars = {'A', 'B', 'C', ...};
int[] probabilities = {5, 2, 4, ...}; // number of tiles with each letter

LinkedList<Character> bag = new LinkedList<Character>();
for (int i = 0; i < chars.length; i++) {
    for (int n = 0; n < probabilities[i]; n++) {
        bag.add(chars[i]);
    }
}

次にbag.shuffle()、タイルをランダム化し、bag.pop()ランダムに 1 つ選択できるようにします。

于 2012-09-10T21:00:28.333 に答える
1

Java での乱数の生成に関するドキュメントを次に示します。

ここで、0 から 95 までのランダムな整数 (96 の可能なバリアント) を生成するとします。

次に、各文字をそれらの数字の 1 つにマップできます。それを行う簡単で汚い方法は、switchステートメントです

switch (randomNumber)
{
    case 0:
        //decide that you want J
    break;
    case 1:
    case 2:
        // maybe you want a letter to have a 2/96 probability
    break;
}

それを行う別の簡単な方法は、文字の配列を使用することです。

Random rand = new Random(new Date().getTime())
char[] charArray = {'A','B','C','C','D','E','F','F','F'};
char chosenChar = charArray[rand.nextInt(0, 96)];
于 2012-09-10T20:37:21.737 に答える
0
Random r = new Random();
char c = (char) r.nextInt(25)+65;

http://www.asciitable.com/

于 2012-09-10T20:48:16.373 に答える
0

あなたができることは次のようなものです:

List<char> letters = new List<char>();
Dictionary<int,List<char>> set1 = new Dictionary<int,List<char>>();
set1.Key = 2;
set1.Value = new List<char>{'A','B'} //blah blah blah

これらの辞書の配列またはリストを作成し、それらを foreach します

foreach (char theChar in set1.Value)
{
  for (int i = 0; i < set1.Key;i++)
  {
    letters.add(theChar);
  }

それから、

Random random = new Random();
char nextchar = letters[random.nextInt(letters.Count - 1)];

選ばれる可能性が高いほど、リストに追加する回数が多くなります。

また、必要に応じて、文字を 1 つの長さの文字列に置き換えることができます。

編集:文字に追加する古い方法は次のとおりです。

for (int i = 0; i < 4; i++) // 4 times
{
    letters.add('a');
}
 for (int i = 0; i < 3; i++) // 4 times
{
    letters.add('b');
}

于 2012-09-10T20:41:23.037 に答える
0

最も楽な解決策は、特定の文字の出現確率に対してコンパクトなコンテナーを必要とすることです。確率関数 (離散分布関数) として機能する HashMap を使用することをお勧めします。このような:

HashMap<Character, Double> map = new HashMap<Character, Double>();
for(Character c : {'J', 'K', 'Q', 'Y', 'Z'}) {
    map.put(c, 1.0 / 96.0);
}
// and so on

念のため、すべての確率の合計が に等しいことを確認するとよいでしょう1.0が、数値は確率の重みとして扱われ、最後に正規化されます。わかりますよね?

純粋に数学的アプローチでは、累積分布関数を作成し、それを元に戻してから、その関数の使用を明示する必要があります。そうすれば、ほぼすべての確率分布で任意のランダム値を生成するソリューションを提供できます。

すぐにやってみましょう:

double sum = 0.0, partialSum = 0.0;
HashMap<Double, Character> dist = new HashMap<Double, Character>();
for(Entry<Character, Double> entry : map.entrySet()) {
    sum += entry.getValue(); // for normalization purpose, if you are really sure
    // that all the probabilities sum up to 1.0, then the first loop is redundant
}
for(Map.Entry<Character, Double> entry : map.entrySet()) {
    dist.put(partialSum / sum, entry.getKey());
    partialSum += entry.getValue(); // the cumulative probability here
}

マップを使用するには、電話するだけです

Random r = new Random();
...
dist.get(r.nextDouble());
于 2012-09-11T22:14:04.180 に答える