微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

算法:在用户定义的区间内随机选择点,以最小的用户定义值分隔

如何解决算法:在用户定义的区间内随机选择点,以最小的用户定义值分隔

我需要开发一种算法,在用户指定的时间间隔内随机选择值。此外,这些值需要由用户定义的最小距离分隔。在我的例子中,值和间隔是时间,但这对于通用算法的开发可能并不重要。

例如用户可以定义三个时间间隔(0900-1200、1200-1500;1500-1800),根据这些值选择 3 个值(每个间隔 1 个)。用户还可以说他们希望这些值至少间隔 30 分钟。因此,值不能1159,1201,1530,因为前两个元素仅相隔 2 分钟。

最有效的算法将获得几百分(无论我能给出多少分)。答案可能与语言无关,但首选以伪代码或 JavaScript 形式给出的答案。

注意:

  • 间隔的数量和每个间隔的长度完全由用户决定。
  • 随机选择的两个点之间的距离也完全由用户决定(但必须小于下一个间隔的长度)
  • 用户定义的间隔不会重叠
  • 用户定义的时间间隔(例如 0900-1200、1500-1800、2000-2300)之间可能存在间隔

我已经有了以下两种算法,希望找到计算效率更高的算法:

  1. 随机选择间隔 #1 中的值。如果此值小于用户指定的距离间隔 #2 开始的距离,请在从间隔 #2 随机选择值之前调整间隔 #2 的开始。重复所有间隔。
  2. 从所有区间中随机选择值。遍历选定值的数组并确定它们是否由用户定义的最小距离分隔。如果不是(即值太接近),则随机选择新值。重复直到有效数组。

解决方法

这对我有用,但我目前无法使其“更高效”:

function random(intervals,gap = 1){
    if(!intervals.length) return [];

    // ensure the ordering of the groups
    intervals = intervals.sort((a,b) => a[0] - b[0])

    // check for distance,init to a value that can't exist
    let res = []
    for(let i = 0; i < intervals.length; i++){
        let [min,max] = intervals[i]

        // check if can exist a possible number
        if(i < intervals.length - 1 && min + gap > intervals[i+1][1]){
            throw new Error("invalid ranges and gap")
        }
        // if we can't create a number in the current section,try to generate another number from the previous
        if( i > 0 && res[i-1] + gap > max){
            // reset the max value for the previous interval to force the number to be smaller
            intervals[i-1][1] = res[i-1] - 1
            res.pop()
            i-=2
        }
        else {
            // set as min the lower between the min of the interval and the previous number generated + gap
            if( i > 0 ){
                min = Math.max(res[i-1] + gap,min)
            }
            // usual formula to get a random number in a specific interval
            res.push(Math.round(Math.random() * (max - min) + min))
        }
    }
    return res
}

console.log(random([
    [0900,1200],[1200,1500],[1500,1800],],400))

这就像:

  1. 生成第一个数字 ()
  2. 检查是否可以生成第二个数字(用于间隙规则)
    - 如果可以,生成它并返回第 2 点(但使用第三个数字)
    - 如果我不能,我将前一个间隔的最大值设置为生成的数字,并使其再次生成(以便它生成一个较低的数字)

我无法弄清楚复杂性是什么,因为涉及随机数,但可能会发生这种情况,间隔为 100,在生成第 100 个随机数时,您会发现不能,因此在最坏的情况下如果这可能会从第一个开始生成所有内容。

然而,每次返回,都会缩小区间的范围,所以如果存在,它会收敛到一个解

,

这似乎可以完成工作。解释见代码中的注释...

请注意,此代码不会对您的条件进行任何检查,即不重叠的间隔和间隔大到足以让心智师得到满足。如果条件不满足,可能会产生错误的结果。

该算法允许用每个间隔分别定义两个值之间的最小距离。

还要注意,这个算法中像 900 这样的间隔限制并不表示 9:00 点,而只是 900 的数值。如果你想让间隔代表时间,例如,您必须将它们表示为自午夜以来的分钟数。即 9:00 将变为 540,12:00 将变为 720,15:00 将变为 900。

编辑

使用当前编辑,它还支持在午夜换行(尽管它不支持超过一整天的间隔或最小距离)

//these are the values entered by the user
    //as intervals are non overlapping I interpret
    //an interval [100,300,...] as 100 <= x < 300
    //ie the upper limit is not part of that interval
    
    //the third value in each interval is the minimum
    //distance from the last value,ie [500,900,200] 
    //means a value between 500 and 900 and it must be
    //at least 200 away from the last value

    //if the upper limit of an interval is less than the lower limit
    //this means a wrap-around at midnight.

    //the minimin distance in the first interval is obviously 0
    let intervals = [
      [100,0],[500,200],[900,560,500]
    ]
    //the total upper limit of an interval (for instance number of minutes in a day)
    //lenght of a day. if you don't need wrap-arounds set to 
    //Number.MAX_SAFE_INTEGER
    let upperlimit = 1440; 

    //generates a random value x with    min <= x < max
    function rand(min,max) {
      return Math.floor(Math.random() * (max - min)) + min;
    }

    //holds all generated values
    let vals = []; 
    let val = 0; 

    //Iterate over all intervals,to generate one value 
    //from each interval
    for (let iv of intervals) {
      //the next random must be greater than the beginning of the interval
      //and if the last value is within range of mindist,also greater than
      //lastval + mindist
      let min = Math.max(val + iv[2],iv[0]);

      //the next random must be less than the end of the interval
      //if the end of the interval is less then current min
      //there is a wrap-around at midnight,thus extend the max
      let max = iv[1] < min ? iv[1] + upperlimit : iv[1];
      
      //generate the next val. if it's greater than upperlimit
      //it's on the next day,thus remove a whole day
      val = rand(min,max);
      if (val > upperlimit) val -= upperlimit;
      
      vals.push(val);
    }

    console.log(vals)

您可能会注意到,这或多或少是对您的提案 #1 的一种实现,但我认为没有任何方法可以使其“计算效率更高”。您无法避免从每个间隔中选择一个值,并且始终生成有效数字的最有效方法是在必要时调整间隔的下限。

当然,使用这种方法,下一个数字的选择总是受限于前一个数字的选择。特别是如果两个数之间的最小距离接近区间长度,而前一个选择的数却处于区间的上限。

,

这可以通过将间隔按所需的分钟数分开来简单地完成。但是,可能存在边缘情况,例如给定的间隔比分隔短,甚至更糟的是两个后续间隔比分隔短,在这种情况下,您可以安全地抛出错误。即在 [[900,1500]] 情况下 1500 - 900 < 30 曾经。因此,您最好根据随后的元组检查这种情况,如果它们不满足,则在进一步尝试之前抛出错误。

然后它变得有点毛茸茸的。我的意思是概率论。天真的方法会在 [900,1200] 中选择一个随机值,并根据结果将 30 添加到它并相应地限制第二个元组的底部边界。假设在 [900,1200] 中选择的随机数结果是 1190,那么我们将强制在 [1220,1500] 中选择第二个随机数。这使得第二个随机选择取决于第一个选择的结果,据我从概率课程中记得这是不好的。我相信我们必须找到所有可能的边界并在其中随机选择,然后从每个范围中随机选择两个安全的选择。

要考虑的另一点是,这可能是一长串元组开始。所以我们应该注意不要在每一轮中限制第二个元组,因为它将是下一轮的第一个元组,我们希望它尽可能宽。因此,也许从第一个范围中获取最小可能值(尽可能地限制第一个范围)可能比随机尝试更有效率,这可能(最有可能)在进一步的步骤中产生问题。

我可以给你密码,但由于你没有展示任何尝试,你必须用这根鱼竿自己去钓鱼。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?