【问题标题】:Finding total number of subsequences in an array with consecutive difference = k查找具有连续差异 = k 的数组中的子序列总数
【发布时间】:2021-04-25 15:31:57
【问题描述】:

在给定的数组中,我试图找到子序列的总数,例如:

  • 连续词之间的差不大于3
  • 子序列的第一个元素是数组的第一个元素
  • 子序列的最后一个元素是数组的最后一个元素

例如,在一个数组中:[10,13,7,8,14,200, 876, 11],它有5个符合上述条件的子序列。

我正在尝试一种自下而上的方法。我尝试了以下方法,但它并没有给出所有子序列和输出 4 而不是 5。

我该如何处理?我有一种直觉,该方法可能类似于最长递增子序列,但不确定如何。

【问题讨论】:

  • 您能否提供您的代码给出的 4 个序列?
  • @VFX 已更新 .. 它会打印除 [10,13,11] 之外的所有内容
  • 您只对满足您条件的序列数感兴趣,对吧?你不需要打印实际的序列
  • @VFX No........
  • @VFX 你是否也觉得这是 LIS(最长递增子序列)问题的变体?

标签: javascript arrays algorithm dynamic-programming subsequence


【解决方案1】:

令 f(i) 为满足以下条件的子序列数:

  • 从 A[0] 开始
  • 由 A[i] 结束
  • 连续词之间的差不大于3

那么你的问题的答案就是 f(A.length()-1)。

下面是 C++ 自下而上的代码:

int A[] = {10,13,7,8,14,11};
int f[6];
int n = 6;
    
for (int i=0;i<n;i++) f[i] = 0;
f[0]=1;
for (int i=1;i<n;i++){
  for (int j=0;j<i;j++){
     if (abss(A[i] - A[j]) <= 3)
         f[i] += f[j];
  }
}
cout<<f[n-1]<<endl;//printing the result

这是用 C++ 自顶向下方法编写的代码:

int A[] = {10,13,7,8,14,11};
int n = 6;

int memo[6];//initialized with -1s;

int count(int currIndex){
  if (currIndex == n-1) return 1;
  if (memo[currIndex] != -1) return memo[currIndex];
  
  int res = 0;
  for (int i=currIndex+1 ; i<n ; i++){
      if (abss(A[currIndex] - A[i]) <= 3){
            res += count(i);
      }
  }
    
  memo[currIndex] = res;
  return res;
}

结果将是在第一个索引处调用 count ,如下所示:

count(0);

【讨论】:

  • Here is a translation to JavaScript。我实际上对这个问题的理解还不够,所以我不确定输出是否正确。所以,我希望我没有在某个地方犯错。
  • 好的我会检查你的代码,我的代码打印5正确,你可以在这里运行onlinegdb.com/HyQqH4DX_w
  • 啊,好的 - 那么这会产生相同的输出。有一个小问题 - 我不小心让它打印了整个数组。 Here is the corrected code
  • 如果你不明白逻辑,我可以更详细地解释,所以请告诉我
  • f[i] = 0 initialization 是正常的零初始化,而不是基本情况,就像用零初始化计数器时一样,因为f[i] += f[j] 就像一个计数器,我们需要从零开始。另一方面,基本案例是计算更大案例所需的值
【解决方案2】:

@VFX 已经提出了O(N^2) 解决方案,但在大多数情况下,优化算法将是首选。所以这里有一个O(K*N) 解决方案。
假设您在子序列中的第一个元素是x。下一个元素必须在[x-k, x+k] 范围内。如果您知道该范围内所有值的有效序列数,您也可以在O(K) 中找到当前元素的答案。
更正式地说,算法是:

arr = []              // your list
counter = {}          // a dictionary or hashmap to keep count of sequences
counter[arr[-1]] = 1
for i in range (len(arr)-2 to 0):
    curr_element = a[i]
    sequences = 0
    for x in range (curr_element-k to curr_element+k):
        sequences += counter[x]
    counter[curr_element] += sequences

final_answer = counter[arr[0]]

【讨论】:

    【解决方案3】:

    我刚刚注意到@Abhinav 的答案是优化O(K*N) 的解决方案而不是O(N^2),这对于小型K 来说可以正常工作。
    但是如果需要一个最佳解决方案,我会建议一个O(N*log2(N)) 解决方案,其中找到[x-k,x+k] 范围内的总和可以 使用 Segment TreeBinary Indexed Tree(Fenwick Tree) 在 log2(N) 中完成,其中 Range Sum Query(RSQ) 是这两种数据结构提供的标准操作。

    如果初始数组中的值很大(如 long 或 double),则可以借助 Map 进行数据压缩。
    在这种方法中,您无需担心K,即使它太大了。

    【讨论】:

      猜你喜欢
      • 2015-11-05
      • 2015-07-27
      • 2015-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 2019-03-22
      • 1970-01-01
      相关资源
      最近更新 更多