Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从1-50的生成器生成1-100的随机数_Java_Optimization_Random - Fatal编程技术网

Java 从1-50的生成器生成1-100的随机数

Java 从1-50的生成器生成1-100的随机数,java,optimization,random,Java,Optimization,Random,在最近的一次采访中,我被问到以下问题: 使用给定的getrnd50()方法打印1-100之间的随机数 它生成1-50之间的随机数。每个随机数 只能按随机顺序打印一次。不使用其他随机数生成器 是允许的,我不允许改变 getrnd50() 我想出了下面的代码,它给出了正确的输出 import java.util.Random; public class Test { public static void main(String[] args) { int[] rs = new int[1

在最近的一次采访中,我被问到以下问题:

使用给定的
getrnd50()
方法打印1-100之间的随机数 它生成1-50之间的随机数。每个随机数 只能按随机顺序打印一次。不使用其他随机数生成器 是允许的,我不允许改变
getrnd50()

我想出了下面的代码,它给出了正确的输出

import java.util.Random;

public class Test {

public static void main(String[] args) {
    int[] rs = new int[100];
    int count = 0;
    int k;
    while (count != 100) {

        // I decided to simply multiply the result of `getrnd50()` by 2. 
        // But since that would generate only even numbers,

        k = getrnd50() * 2;

        // I decided to randomly subtract 1 from the numbers. 
        // Which i accomlished as follows.          

        if (getrnd50() <= 25) // 25 is to half the possibilities.
            k--;

        // Every number is to be stored in its own unique location 
        // in the array `rs`, the location is `(number-1)`. 
        // Every time a number is generated it is checked whether it has 
        // already been generated. If not, it is saved in its position, printed and 
        // `count` is incremented.

        if (rs[k-1] == 0) {
            rs[k-1] = k;
            count++;
            System.out.print(k + " ");
        }
    }
}
// This is the method and i am not supposed to touch it.
static int getrnd50() {
    Random rand = new Random();
    return (1 + rand.nextInt(50));
}

}
import java.util.Random;
公开课考试{
公共静态void main(字符串[]args){
int[]rs=新的int[100];
整数计数=0;
int k;
而(计数!=100){
//我决定简单地将'getrnd50()'的结果乘以2。
//但由于这只会产生偶数,
k=getrnd50()*2;
//我决定从数字中随机减去1。
//我的解释如下。

如果(getrnd50()因为100/50是一个整数,这很容易。因为50/(100/50)是一个整数,这就更容易了

如果您没有完全理解,下面是一些示例代码:

int rnd1 = getrnd50();
int rnd2 = getrnd50();
if (rnd1 % 2 == 0)
{
    rnd2 += 50;
}
return rnd2;
以下是一个概要:

  • 在1和50之间随机选择的两个数字称为ab
  • 如果a为偶数,则将50加到b
  • 返回b
如果需要,您可以将其制作为一行:

return getrnd50() + getrnd50() % 2 * 50;
这有点太模糊了

编辑:我知道问题其实是要求一个无序列表,而不是一个随机整数序列

这可以通过创建一个从1到100的列表,并进行100次随机交换来实现,就像Fisher-Yates shuffle一样。我认为Fisher-Yates shuffle的绝对最小调用数是93次(使用公式
ceil(log50(100!))
),但使用更简单的算法,可以使用200次

简单的算法是将100个元素中的每一个替换为100个元素中的一个随机元素。要选择的数字将由上述生成器从1-100生成

例如:

for (int i = 0; i < 100; i++)
{
    swap(i, getrnd100() - 1); // - 1 for zero base!
}
for(int i=0;i<100;i++)
{
交换(i,getrnd100()-1);//-1表示零基数!
}
下面是一些完整的代码:

int[] result = new int[100];
for (int i = 0; i < 100; i++)
{
    result[i] = i + 1;
}
for (int i = 0; i < 100; i++)
{
    int j = (getrnd50() + getrnd50() % 2 * 50) - 1;
    int tmp = result[i];
    result[i] = result[j];
    result[j] = tmp;
}
return result;
int[]结果=新的int[100];
对于(int i=0;i<100;i++)
{
结果[i]=i+1;
}
对于(int i=0;i<100;i++)
{
int j=(getrnd50()+getrnd50()%2*50)-1;
int tmp=结果[i];
结果[i]=结果[j];
结果[j]=tmp;
}
返回结果;
(免责声明:我不懂Java,也没有测试过。)


最佳情况200,最坏情况200,平均情况200。

关键是不要检查您以前是否生成过数字,如果只查找剩余的1个数字,这将非常昂贵,而是按顺序生成1-100个数字,然后洗牌

在您的代码中,当您在100个数字中生成99个时,您将循环生成随机数,直到找到剩余的1个数字。这就是为什么您的版本中的平均情况如此糟糕的原因

如果只是对数组进行洗牌,则只需要随机数的数量与洗牌操作的数量相同,洗牌操作的数量与输出数字的数量相同

(有关洗牌的详细信息,请查阅洗牌,特别是可以就地生成洗牌数组的由内而外的变体)

要生成随机数,您需要一个变量生成器,而不是一个固定的1-50生成器。您可以通过多种方式来实现这一点,但如果您确实希望输出在可能的状态之间具有良好的分布,请小心在结果中引入歪斜

例如,我建议使用整数位数的位进行移位,而不是尝试使用模。如果值超出所需的范围,这确实会涉及一定数量的循环,但如果无法修改原始随机数生成,您的手会有些束缚

static int bits = 0;
static int r100 = 0;

static int randomInt(int range)
{
    int ret;

    int bitsneeded = 32 - Integer.numberOfLeadingZeros(range - 1);

    do {
            while(bits < bitsneeded)
            {
                    int r = (getrnd50()-1) * 50 + getrnd50()-1;
                    if(r < 2048)
                    {
                            r100 <<= 11;
                            r100 |= r;
                            bits += 11;
                    }
            }
            ret = r100 & ((1 << bitsneeded) - 1);
            bits -= bitsneeded;
            r100 >>=  bitsneeded;
    } while(ret >= range); 

        return ret + 1;
}
静态整数位=0;
静态int r100=0;
静态int randomInt(int范围)
{
int ret;
int bitsneed=32-整数。前导零的数量(范围-1);
做{
while(位
此实现将为100值随机数组使用150个随机数的区域。这比模版本差,但比输入范围的2倍要好,这是原始版本的最佳情况。如果随机生成是真正随机的,那么最坏的情况仍然是无穷大,但随机生成ion通常不是这样工作的。如果是这样的话,考虑到约束条件,我不确定不符合实际的结果

为了举例说明,由于结果很微妙,下面是我建议的随机例程与模版本的对比图:


总之,我认为虽然你的随机生成有点低效,而且可以改进,但面试官所寻求的真正的大赢家,是在一开始就不需要那么多随机数,通过洗牌而不是以不断降低的概率重复搜索。

代码的性能损失他在那条线上

if (getrnd50() <= 25)

if(getrnd50()Ok,那么允许您打印最后一组丢失的n个数字,而不必由随机数生成器生成

如果是这样的话,您可以利用递归并在每次调用时减小集合的大小,直到只有n=2,然后调用getrnd50()一次。当您递归返回时,只需在每个集合上打印缺少的数字。

List lint;
 List<Integer> lint ; 

  public void init(){
      random = new Random();
      lint = new LinkedList<>();
      for(int i = 1 ; i < 101; ++i) {
          lint.add(i); // for truly random results, this needs to be randomized.
      }
  }

  Random random ; 
  public int getRnd50() {
      return random.nextInt(50) + 1;
  }

  public int getRnd100(){

      int value = 0;
      if (lint.size() > 1) {
          int index = getRnd50()%lint.size();
          value = lint.remove(index); 
      } else if (lint.size() == 1 ) {
          value = lint.remove(0);
      }      

      return value;      
  }
公共void init(){ 随机=新随机(); lint=newlinkedlist(); 对于(int i=1;i<101;++i){ lint.add(i);//对于tr
import java.util.*;
import java.lang.*;

class Main {
    public static void main(String... args) {
        int samples = 100;

        // all the numbers [1, 100]
        int[] nums = new int[samples];
        for (int i = 0; i < samples; i++) nums[i] = i + 1;

        for (int i = samples - 1; i > 0; i--) {
            int swapWith = nextInt(i + 1);

            // swap nums[i] and nums[swapWith]
            if (swapWith == i) continue;
            int tmp = nums[swapWith];
            nums[swapWith] = nums[i];
            nums[i] = tmp;
        }
        System.out.println("calls/sample " + (double) calls / samples);
        System.out.println(Arrays.toString(nums));

        int[] count49 = new int[49];
        for (int i = 0; i < 49 * 10000; i++)
            count49[nextInt(49) - 1]++;
        int[] count54 = new int[54];
        for (int i = 0; i < 54 * 10000; i++)
            count54[nextInt(54) - 1]++;
        System.out.println("Histogram check (49): " + Arrays.toString(count49));
        System.out.println("Histogram check (54): " + Arrays.toString(count54));

    }

    // keep track of the range of values.
    static int maxRandom = 1;
    // some random value [0, maxRandom)
    static int rand100 = 0;

    static int nextInt(int n) {
        while (maxRandom < 10 * n * n) {
            maxRandom *= 50;
            rand100 = rand100 * 50 + getrnd50() - 1;
        }
        int ret = rand100 % n;
        maxRandom = (maxRandom + n - 1) / n;
        rand100 /= n;
        return ret + 1;
    }

    static final Random rand = new Random();
    static int calls = 0;

    static int getrnd50() {
        calls++;
        return (1 + rand.nextInt(50));
    }
}
calls/sample 1.509