[英]How do I generate random letters in java based on probability?
我無法根據概率生成隨機字母。
例如,字母J,K,Q,Y,Z的出現概率均為1/96。 其他字母也使用類似的過程(概率更高)。
有人可以告訴我該怎么做嗎?
進行具體編輯:我正在編寫一種名為“ getRandomLetter”的方法,該方法基於概率分數返回隨機字母的char。
從具有特定概率的離散元素集中進行選擇的典型方法是選擇一個隨機浮點數,並找出其位於哪個范圍內。我將舉例說明。 假設您在三個字母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個字母執行此操作,那么寫出所有26種if
- else
語句的情況將很痛苦。 您可以事先准備一個字符數組及其各自的概率,
char[] chars = {'A', 'B', 'C', ...};
double[] probabilities = {0.01, 0.02, 0.05, ...};
然后你就可以自動所有if
有這樣的循環-ing:
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
,然后使用rnd.nextInt(96)
選擇0到95(含rnd.nextInt(96)
之間的整數,而不是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];
現在,如果您要進行一些操作,例如從袋子中畫出Scrabble瓷磚,那將變得更加棘手,因為這是一個無需替換的采樣過程,即,每次繪制后概率都會發生變化。 我認為在這種情況下,更好的方法是實際使用一個集合來模擬袋子,然后為上面帶有字母的每個圖塊實際添加字母的一個副本。 您仍然可以使用之前相同的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()
貼,而bag.pop()
允許您隨機選擇一個。
現在,假設您生成一個介於0到95(含)之間的隨機整數(96個可能的變體)
然后,您可以將每個字母映射到這些數字之一。 一個簡單而骯臟的方法是使用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)];
您可以做的是這樣的:
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)];
您希望它被選擇的次數越多,將其添加到列表中的次數就越多。
還可以:如果需要,可以將char替換為一個長度的字符串。
編輯:這是添加字母的舊方法:
for (int i = 0; i < 4; i++) // 4 times
{
letters.add('a');
}
for (int i = 0; i < 3; i++) // 4 times
{
letters.add('b');
}
等等
Random r = new Random();
char c = (char) r.nextInt(25)+65;
最令人愉悅的解決方案是為給定字母的出現概率要求使用緊湊的容器。 我建議使用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());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.