【问题标题】:storing random values in arrays considering duplicates考虑重复在数组中存储随机值
【发布时间】:2011-02-15 09:46:45
【问题描述】:

这是this post 的新版本,以便将编程问题与概率问题隔离开来。

我想存储一些例如数组中 25 个随机生成的 1 到 365 之间的数字。但我需要跟踪重复项。以下是我的想法:

  • 创建 4 个数组:一个主数组,一个用于 2 个副本的数组,一个用于 3 个副本的数组和一个用于 3 个以上副本的数组

  • 将每个生成的数字一一添加到主数组中。但在这样做之前,请遍历数组以查看它是否已经存在。如果是这样,将其添加到第二个数组中,但在此之前重复上述过程,依此类推

在过程结束时,我可以计算每个数组中的非空值,以了解我有多少个唯一数字,有多少个出现两次等

这似乎不是一个非常有效的算法。有什么改进的建议吗?

我建议的方法可以被认为是大 O(n),即线性吗?

【问题讨论】:

  • 您能否详细说明“跟踪重复项”?您想从这些数据中提取什么信息?
  • 例如。您是否在估计两个随机的人共享同一生日的概率?
  • @Blorgbeard,我已经改写了这篇文章。我将在 1 和 365 之间生成 25 个随机数。我需要跟踪生成的任何数字的两倍或三倍或更多。当然,我不会总是得到重复,甚至更不可能重复三次,但我可能......所以我想捕获/计算此类事件
  • 您需要保留生成数字的顺序吗?
  • 我也相信你的算法在技术上是 O(1),但效率很低。由于最多有 365/6 个不同的生日,因此每个数组的最大大小为 365 个元素。遍历一个恒定大小的数组是 O(1),因为它不依赖于生成的生日数。但这并不意味着它很快。如果你知道你总是会生成

标签: java arrays algorithm


【解决方案1】:

为什么要使用数组? HashMap 或其他映射结构似乎更有意义。以下是我的做法。

  1. 实例化一个从生日到整数的新的空哈希映射
  2. 随机生成生日。
  3. 检查生日是否在哈希图中。如果不是,则将其添加为“1”。是的,在那个生日增加值。

现在您可以获取由哈希图中的键数生成的唯一日期数,以及有关值的重复数的任何信息。

【讨论】:

  • 感谢您的建议。我将需要了解哈希表。在 SO 上找到了一个很好的起点:stackoverflow.com/questions/2489169/…
  • @All,我会接受建议计算效率最高的方法的答案。需要一些时间来评估答案。感谢您迄今为止的参与!
  • 我自己会使用HashMap<Integer,Integer>,但如果您愿意,也可以使用Hashtable。而且我不会预先初始化任何东西,只要每次生成一个新数字时检查它是否已经在地图中。如果是,则增加其计数,如果没有,则将其插入计数 1。
  • @biziclop - 编辑建议使用 hashmap 而不是 hashtable;我的 Java 有点生锈了。通过initialize,我只是想实例化对象,我认为从“空”中可以清楚地看到。
  • @Baba - 似乎HashTable 已被弃用,您应该研究HashMap (您的链接中接受的答案涵盖了这一点)。基本上,您需要知道它是从键(此处为生日)到值(此处为出现次数)的映射。您可以通过给定键查找值,枚举所有键/值,并执行一些其他有用的操作。
【解决方案2】:

这是我认为可以解决问题的方法。

  1. 有两个数组:一个包含生日的主数组,一个包含重复次数的数组。
  2. 随机生成生日。
  3. 循环遍历主数组,看看它是否已经存在。
  4. 如果不存在,则将其添加到主数组并在相同的索引位置,将 1 存储在另一个数组中。 (如果你把生日加到master[3],把1存入number[3])
  5. 如果它已经存在,则将一个添加到另一个数组中的相应索引。
  6. 现在您的主数组将包含生成的生日,而另一个数组中的相应索引将包含重复的次数。 (master[0] 有一个日期,number[0] 有日期重复的次数)。

希望这会有所帮助。

【讨论】:

  • 我喜欢它——简单而高效。有利于清晰的代码对家庭作业有好处(我相信这个问题是..)
  • @Harish,是的,这听起来比我最初的想法要好得多。感谢那!一些阵列位置可能仍然无人居住的事实有什么问题吗? @Blogbeard,你是对的,我已经相应地更新了帖子标签
  • @Baba,首先用零填充你的两个数组,然后开始你的进程。这样会更容易。
  • @SO 人,如果你已经解决了,能否请你发布工作示例,以便进一步参考
  • @Deepak,这个问题没有唯一的解决方案。此处发布的所有建议都有效。有些在效率方面比其他的要好。
【解决方案3】:

在红宝石中:

birthdays = {}.tap{|h| h.default = 0}
25.times { birthdays[rand(364)+1] += 1 }

puts birthdays.keys # all the uniq birthdays
puts birthdays.inspect # all birthdays with counts

想法是使用哈希或固定大小的数组,其中键对应于生日,值是选择生日的次数

问题是你会失去生日的顺序,因为它们只是哈希/数组中的键,但如果原始顺序不重要,你总是可以通过这样做得到随机的生日序列

birthdays.keys.shuffle

【讨论】:

    【解决方案4】:

    根据您需要生成随机列表的次数,您可能会考虑创建所有数字的列表,然后使用shuffle sort 对它们进行置换,然后您可以从数组中拉出连续的块,这将是以随机顺序且唯一。因此,在最坏的情况下,性能将是 O(所有数字的大小)+O(所需数字的大小),最好的情况是 O(所需数字的大小)。一个例子:

    private int[] numbers;
    private int numberIndex=Integer.MAX_VALUE;
    private void initNumbers(){
      int[] numbers = new int[365];
      for(int i=0;i<365;i++){
        numbers[i] = i+1;
      }
      shuffleSort(numbers);
      numberIndex = 0;
    }
    
    public int[] getRandom(int howMany){
      if(numberIndex > numbers.length-howMany){
        initNumbers();
      }
      int[] ret = new int[howMany];
      for(int i=0;i<howMany;i++){
        ret[i] = numbers[numberIndex++];
      }
      return ret;
    }
    
    private void shuffleSort(int[] numbers){
      Random r = new Random();
      int tmp=0, swap=0;
      for(int i=numbers.length-1;i>0;i--){
        swap = r.nextInt(i);//random number between 0 and i
        tmp = numbers[i];
        numbers[i] = numbers[swap];
        numbers[swap] = tmp;
      }
    }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-10
      • 1970-01-01
      • 2021-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多