【问题标题】:How to have unique random number?如何拥有唯一的随机数?
【发布时间】:2010-08-03 11:12:33
【问题描述】:

这就是我在 1 到 6 之间生成唯一编号并从可绘制文件夹中获取适当图像的方式。

Random rand = new Random();
// n = the number of images, that start at idx 1
rndInt = rand.nextInt(6) + 1; 
String imgName = "card" + rndInt;
int id = getResources().getIdentifier(imgName, "drawable", getPackageName());
imgView.setImageResource(id);

我想要的是,我必须调用这个方法 7 次,每次这个方法都应该返回一个唯一的随机数。这样已经选择的数字都不会再次出现。

【问题讨论】:

  • 如果只有 6 个可能的值,你将如何获得 7 个唯一的数字?
  • “唯一”和“随机”是互斥的。你不能两者兼得。
  • @Dan Dyer 对不起。我将其更改为 7。@greg D.. 伙计,请接受公认的答案 ..该代码正在创建一个唯一的赎金号。
  • @Greg D 我猜他想要数字 1 到 N 的随机排列
  • 您不是在寻找一个唯一的随机数,而是在寻找随机顺序的数字 1 到 6。

标签: java random


【解决方案1】:

解决此类问题的常用方法是创建一个包含每个可能值的列表并将其随机排列(使用Collections.shuffle)。然后,每次您需要一个值时,您都会使用列表中的一项。这将确保您不会多次使用相同的值,但仍允许随机顺序。

【讨论】:

  • 您似乎正在使用它来洗牌。把所有的牌都装好,然后洗牌不是更好吗?该方法类似于此答案。
  • +1 比公认的答案好得多。我想知道您的是否已被接受,如果它有代码。
【解决方案2】:

这是一个示例类,它使用 Dan Dyer 建议的方法创建随机排列。它确保每个 .next() 调用都会给出一个新数字,直到构造函数中给出的数字。之后,它环绕并再次给出相同的序列。 这对于随机播放列表很有用。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class RandomPermutation{
    private List<Integer> list;
    private int index;

    /**
     * Create a random permutation the sequence of numbers 0, 1, ... , n - 1.
     * @param n Range specifier, must be positive
     */
    public RandomPermutation(int n) {
        if (n <= 1) {
            throw new IllegalArgumentException(
                    "Positive number expected, got: " + n);
        }
        list = new ArrayList<Integer>();
        newList(n);
    }

    /**
     * Creates a new list
     */
    public void newList(int n) {
        index = -1;
        list.clear();
        for (int i = 0; i < n; i++) {
            list.add(i);
        }
        Collections.shuffle(list);
    }

    /**
     * Retrieve the next integer in sequence. 
     */
    public int next() {
        index = (index + 1) % list.size();
        return list.get(index);
    }
}

顺便说一句。不要使用 Snake 使用的方法。 这不仅是因为一旦使用了所有数字,它就会冻结。那是可以解决的。 问题更多的是,随着 listIdontWantAnymore 中的数字越来越多,该过程的运行速度越来越慢。只有 6 个数字,这不是问题,但如果范围很大,它可能会导致相当大的减速。考虑在 10000 个数字之间进行选择。在选择了 9900 个号码后,有 1% 的机会获得一个好号码。在 9990 个数字之后,有 0.1% 的机会获得一个好的数字等等。

这是一个如何使用该类的示例:

static RandomPermutation randomPerm = new RandomPermutation(7)

int NextRandomNumber() {
    return randomPerm.next() + 1;
}

【讨论】:

  • 感谢 zeriab,我实现了你的方法,以及它的工作 f9。你能告诉我一件事吗,比如你必须看到一个计时器,倒数计时器,显示从 10 到 0 的值,在视图中可见。我怎样才能显示随机数在我的视图中不断变化。再次感谢队友
【解决方案3】:

这是最简单的代码,无需任何重复即可将其存储到数组中:

Random rand = new Random();
int[] ar;
ar = new int[5];

int random = 0;
int [] result_arr=new int[5];
boolean flag=false;

for(int i=0;i<5;i++)
{  
    ar[i]=0;

    do{
        random =rand.nextInt(10);
        flag=false;
        for(int j=0;j<i;j++)
        {
            if(ar[j]==random)
            flag=true;
        }
        if(!flag)
        {
            ar[i]=random;
            break;
        }
     }
     while(true) ;
}

这将在数组中创建唯一的数字

【讨论】:

    【解决方案4】:

    对于您的特定用例,这应该可以解决问题。

    Random rand = new Random();
    // n = the number of images
    List<String> imgNames = new ArrayList<String>(n);
    for (int i = 0; i < n; i++) { 
        imgNames.add("card" + (i + 1)) 
    }
    while (!imageNames.isEmpty()) {
        String imgName = imgNames.remove(rand.next(imageNames.size());
        int id = getResources().getIdentifier(imgName, "drawable", getPackageName());
        imgView.setImageResource(id);
    }
    

    请注意,随着n 变大,这不能很好地扩展。对于ArrayListLinkedList,删除操作是O(n)。但是对于成百上千的n,这与加载和显示图像相比可能微不足道。

    此外,正如 cmets 所指出的,“唯一随机数”在术语上是矛盾的。您所追求的是从1n 的一组数字的随机排列。我的解决方案在没有明确的“改组”步骤的情况下为您提供了这一点,这对于您的用例来说已经足够了。

    【讨论】:

    • 我会说很明显,“唯一随机数”意味着不应多次选择同一个样本。附带说明:LinkedList 上的 removeFirst() 操作是 O(1)。
    • @Zeriab - “LinkedList 上的 removeFirst() 操作是 O(1)”。这有什么关系?该算法不使用该方法。
    • @Zeriab - “唯一随机数”对您来说可能很清楚,但从数学角度来看,这是无稽之谈。有点像谈论允许重复的集合。
    • 一个唯一(和)随机的数字。相对于其他呼叫而言是独一无二的。随机数字应该在 1,2,...,6,7 中随机选择。我不明白为什么从数学角度考虑这两个约束的结合是无稽之谈。我是否遗漏了一些歧义?
    • 你说得对,我提到的 removeFirst() 与你的例子无关。您可以使用红黑树 (TreeSet),其删除操作在 O(lg) 中运行。
    【解决方案5】:

    生成一个数字列表,其中包含您将使用的每个数字。 (这很好,因为我们谈论的是一个小范围,其中“N”是“小于一千”)

    当你选择一个数字时,选择一个介于 0 和 sizeof(list) 之间的随机索引,该数字将成为该列表的索引。

    删除该列表索引并返回数字。

    (读者可以通过练习来确定此处适合使用哪种“列表”。)

    【讨论】:

      【解决方案6】:

      Use a linear congruential generator with appropriately chosen parameters.

      【讨论】:

        【解决方案7】:

        创建一个您已经获得的可能性的静态列表。

        static ArrayList<int> listIdontWantAnymore = new ArrayList<int>();
        
        int NextRandomNumber() {
            Random random = new Random();
            int myRandomInt;
        
            do {
                myRandomInt = random.NextInt(6) + 1;
            } while(listIdontWantAnymore.Contains(myRandomInt));
        
            listIdontWantAnymore.Add(myRandomInt);
        
            // now your 'myRandomInt' is what you want it to be.
            return myRandomInt;
        }
        

        【讨论】:

        • 我认为任何像这样的解决方案都应该有故障安全系统以避免令人讨厌的死锁。结局可能很糟糕;)
        • @shishir.bobby:不,这并不完美。那绝对是可怕的。请,请不要使用这个“解决方案”。
        • 尝试运行它...假设限制为 1000,您会注意到它很慢。在它生成 999 个数字后,统计上它需要 1000 次尝试才能获得最后一个数字。这意味着该算法的复杂度将是 O(n^2) - 这对于如此简单的任务来说太可怕了。
        • @Max:假设一个完美的分布。我担心它会比 O(n^2) 更糟糕。
        • @shishir.bobby:向下滚动并选择任何其他答案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-05
        • 2013-03-19
        • 2012-02-02
        • 2016-05-09
        相关资源
        最近更新 更多