arrays - 如何创建 n 个随机长度的字符串,其总和等于给定的数量?

标签 arrays algorithm random

我正在尝试创建一种算法来创建随机长度的 n 字符串,其总和等于给定的数量。

一个更清楚的例子:

total = 20;
n = 7;

strings = ['aaaa', 'a', 'aaaaaaa', 'aa', 'aaa', 'aa', 'a'];

所以我有 7 个随机长度的字符串,它们各自长度的总和是(除非我计算错误)20。

直到现在我想出了这个递归函数:

gaps = [];
function createGapsArray(total, n) {
    if (n == 1) {
        var gapLength = total;
    } else {
        var gapLength = getRandomInt(1, total / 2);
    }

  var gap = "";
  for (var i = 0; i < gapLength; i++) {
    gap += "a";
  }
  gaps.push(gap);

  if (n > 1 && total > 0) {
    createGapsArray(total - gapLength, --n);
  }
}

这实际上行不通。通常它会在生成我想要的所有 n 段之前完成。通过我所做的一些测试,似乎将总数除以 4 而不是 2 就可以完成工作。喜欢:

var gapLength = getRandomInt(1, total / 4);

但是这个约束的选择是任意的。我想知道是否有更好的方法。

此外,我知道通过我的方法,算法可能会在开始时生成较长的段,在最后生成较小的段。我不介意均匀分布,但这没什么大不了的,因为对于我需要的,我可以在完成后简单地洗牌数组。

最佳答案

这个问题类似于“找到一个随机集合的k个数字,其总和为N”。这个答案的原始版本使用了一个简单的解决方案,如果数字是连续的(即 float ),该解决方案是无偏的:生成 [0, N] 范围内的 k-1 个数字,对它们进行排序,将 0在开头和结尾的 N,然后找出连续元素之间的差异。但是由于没有小数字符,我们需要数字是整数并且上述算法对包含 0 的集合有偏见(在连续情况下得到 0 的概率无穷小,但在离散情况下很重要)。

生成非空整数解的无偏解是在 [1, N-1] 范围内找到整数的随机 (k-1) 组合。要找到随机组合,请使用范围随机洗牌的前 k-1 个元素(使用 Fisher-Yates 洗牌)。然后对组合进行排序(如有必要)并在前面加上 0;这些值是每个字符串的起始位置(以便下一个值是结束位置。)

这不会产生空子串,因为每个子串都有一个唯一的起点。要包含空子字符串,请使用上面的 N+k 而不是 N,然后将每个范围缩小 1:如果索引已排序,您可以通过从 i 中减去 i 来实现th 索引。

在 Python 中:

from random import sample
def random_split(str, k):
    v = [0] + sorted(sample(range(1, len(str)), k-1)) + [len(str)]
    return [str[v[i]:v[i+1]] for i in range(k)]

def random_split_allow_empty(str, k):
    v = [0] + sorted(sample(range(1, len(str)+k), k-1)) + [len(str)+k]
        return [str[v[i]-i:v[i+1]-i-1] for i in range(k)]

在 Javascript 中:

function shuffle(vec, k) {
  for (let i = 0; i < k; ++i) {
    let r = i + Math.floor(Math.random() * (vec.length - i));
    let t = vec[r];
    vec[r] = vec[i];
    vec[i] = t;
  }
  return vec;
}

function random_partition(N, k) {
  let v = [];
  for (let i = 1; i < N; ++i) v[i-1] = i;
  shuffle(v, k - 1);
  v[k-1] = 0;
  return v.slice(0, k).sort((a,b)=>a-b);
}

function random_split(s, k) {
  return random_partition(s.length, k).map(
    (v, i, a) => s.slice(v, a[i+1]));
}

function random_split_allow_empty(s, k) {
  return random_partition(s.length + k, k).map((v,i)=>v-i).map(
    (v, i, a) => s.slice(v, a[i+1]));
}

关于arrays - 如何创建 n 个随机长度的字符串,其总和等于给定的数量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44374011/

相关文章:

arrays - 如何在CUDA Fortran中分配共享内存阵列?

algorithm - 数据压缩 - 指数分布的机器学习

python - random.randint(1,10) 会返回 11 吗?

.net - 使用鼠标移动和击键来生成加密熵(如 MEGA 上所示)

java - 离散余弦变换实现

c++ - 遍历成员函数的结果

c - C将值存储到数组中而不覆盖的字符串

java - Arrays 类型中的方法 asList(T[]) 不适用于参数 (int, int)

ruby-on-rails - 如何用数组中的空格替换破折号

javascript - 扫雷扩展算法