簡體   English   中英

算法:在用戶定義的區間內隨機 select 個點,以用戶定義的最小值分隔

[英]Algorithm: randomly select points within user-defined intervals, separated by minimum user-defined values

我需要開發一種算法,在用戶指定的時間間隔內隨機選擇值。 此外,這些值需要按用戶定義的最小距離分開。 在我的情況下,值和間隔是時間,但這對於通用算法的開發可能並不重要。

例如:用戶可以定義三個時間間隔(0900-1200、1200-1500;1500-1800),根據這些時間間隔選擇 3 個值(每個間隔 1 個)。 用戶也可以說他們希望這些值至少相隔 30 分鍾。 因此,值不能1159, 1201, 1530因為前兩個元素僅相隔 2 分鍾。

最有效的算法將獲得幾百分(無論我能給出多少分)。 答案可以與語言無關,但首選偽代碼或 JavaScript 的答案。

筆記:

  • 間隔的數量和每個間隔的長度完全由用戶決定。
  • 兩個隨機選擇的點之間的距離也完全由用戶確定(但必須小於下一個區間的長度)
  • 用戶定義的間隔不會重疊
  • 用戶定義的間隔(例如,0900-1200、1500-1800、2000-2300)之間可能存在間隙

我已經有以下兩種算法,並希望找到計算效率更高的算法:

  1. 間隔 #1 中隨機 select 值。 如果此值小於用戶指定的距間隔 #2 開始的距離,請在從間隔 #2 中隨機選擇一個值之前調整間隔 #2 的開始。 重復所有間隔。
  2. 來自所有區間的隨機 select 值。 循環遍歷選定值的數組並確定它們是否被用戶定義的最小距離分開。 如果不是(即,值太接近),隨機 select 新值。 重復直到有效數組。

這對我有用,我目前無法使其“更高效”:

 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. 檢查是否可以生成第二個數字(用於間隙規則)
    - 如果可以,生成它並將 go 返回到第 2 點(但使用第三個數字)
    - 如果我不能,我將前一個間隔的最大值設置為生成的數字,並讓它再次生成它(以便它生成一個較低的數字)

我無法弄清楚復雜性是什么,因為涉及到隨機數,但可能會發生 100 個間隔,在第 100 個隨機數的生成時,你會看到你不能,所以在最壞的情況下,這可能go 從第一個返回生成所有內容。

但是,每次返回時,它都會縮小區間的范圍,因此如果存在,它將收斂到一個解

這似乎可以完成這項工作。 有關解釋,請參閱代碼中的注釋...

請注意,此代碼不會對您的條件進行任何檢查,即非重疊間隔和間隔大到足以讓心靈師得到滿足。 如果條件不滿足,可能會產生錯誤的結果。

該算法允許分別用每個間隔定義兩個值之間的最小距離。

另請注意,在此算法中,像 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, 300, 0], [500, 900, 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,1200],[1200,1500]]情況下1500 - 900 < 30是。 因此,您最好根據后續元組檢查這種情況,如果它們不滿足,則在進一步嘗試之前拋出錯誤。

然后它變得有點毛茸茸。 我的意思是概率。 一種天真的方法會在[900,1200]中選擇一個隨機值,並根據結果將其添加30並相應地限制第二個元組的底部邊界。 假設如果在[900,1200]中選擇的隨機數是1190 ,那么我們將強制在[1220,1500]中選擇第二個隨機數。 這使得第二個隨機選擇取決於第一個選擇的結果,據我從概率課程中記得,這不好。 我相信我們必須找到所有可能的邊界並在其中做出隨機選擇,然后從每個范圍中做出兩個安全的隨機選擇。

要考慮的另一點是,這可能是一長串要開始的元組。 所以我們應該注意不要限制每輪中的第二個元組,因為它將是下一輪的第一個元組,我們希望它盡可能寬。 因此,也許從第一個范圍中獲得最小可能值(盡可能限制第一個范圍)可能比隨機嘗試更有效率,隨機嘗試可能(最有可能)在進一步的步驟中產生問題。

我可以給你代碼,但由於你沒有展示任何嘗試,你必須用這根魚竿解決 go 並自己釣魚。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM