如何根据概率在java中生成随机字母?

时间:2012-09-10 20:30:52

标签: java random probability

我无法根据概率生成随机字母。

例如,字母J,K,Q,Y,Z各自具有1/96的概率。其他字母也使用类似的过程(概率较高)。

有人可以告诉我该怎么做吗?

编辑具体:我正在编写一个名为“getRandomLetter”的方法,该方法根据概率分数返回一个随机字母的字符。

5 个答案:

答案 0 :(得分:3)

从具有特定概率的离散元素集中进行选择的典型方法是选择一个随机浮点数并找出它所在的范围。我将用一个例子来解释。假设您在三个字母A,B和C中进行选择,概率分别为0.255,0.407和0.338。您可以计算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';
}

如果您使用字母表中的所有26个字母执行此操作,则写出if - 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的随机整数而不是浮点数。只需使用int代替double s,然后使用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];

现在,如果你正在做一些事情,比如从包中画出拼字游戏牌,那么它就会变得更加棘手,因为这是一个无需替换的抽样过程,即每次抽签后概率都会发生变化。我认为在这种情况下更好的方法是实际使用一个集合来模拟包,然后为每个包含该字母的图块添加一个字母副本。您仍然可以使用之前的相同charsprobabilities数组循环执行此操作:

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 :(得分:1)

Here's some documentation on generating random numbers in java.

现在,假设您生成0到95之间的随机整数(96种可能的变体)

然后,您可以将每个字母映射到其中一个数字。一个简单而肮脏的方法就是切换语句

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)];

答案 2 :(得分: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 (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)];

您希望选择的次数越多,您在列表中添加的次数就越多。

另外:如果需要,你可以用一个长度的字符串替换字符。

编辑:这是添加到字母的旧方法:

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

答案 3 :(得分:0)

Random r = new Random();
char c = (char) r.nextInt(25)+65;

http://www.asciitable.com/

答案 4 :(得分: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());