在列表中查找升序三元组

时间:2012-10-16 06:40:01

标签: algorithm list

我在编程面试中遇到了这个问题,现在还不知道。

  

长度为n的列表,其中的元素都是没有顺序的正整数。   为了找出所有可能的三元组(a,b,c),a< b< c,列表中的c之前的b和b之前出现a。

     

分析算法的时间复杂度。

3 个答案:

答案 0 :(得分:4)

没有一般算法可以比O(n ^ 3)更快,因为给定不同元素的排序输入然后输出将具有大小O(n ^ 3),因此仅产生输出将花费时间成比例。实际上,即使是随机生成的整数列表,在常数因素之前也会有n ^ 3三倍。

给定您可以简单地按列表顺序迭代所有可能的三元组,并将它们按排序顺序进行比较。这种天真的解决方案已经是渐近最好的解决方案(即O(n ^ 3))

for (int i = 0; i < n; i++)
    for (int j = i+1; j < n; j++)
        for (int k = j+1; k < n; k++)
            if (X[i] < X[j] && X[j] < X[k)
                output(X[i],X[j],X[k])

我怀疑你的问题陈述中可能有转录错误 - 否则问题应该是一个非常简单的短编码练习。

答案 1 :(得分:3)

如果已知只有一小部分三元组(比如k),那么您可能更愿意通过存储指向前一个最小元素的指针来找到所有三元组。

算法

准备一个空的数据结构(可能的选择稍后描述)。

准备一个长度为n的空数组B.

然后对于列表中的每个元素c:

  1. 使用数据结构将列表中最新元素的索引(在数组B中)存储为小于c(如果存在)。
  2. 在数据结构中存储c(及其索引在原始列表中)
  3. 然后使用数组B查找小于c的所有元素b,然后再次查找小于b的所有元素,并将所有这些组合作为输出三元组发出。
  4. 数据结构

    数据结构需要能够存储值,位置对,以便在值小于c的所有元素上轻松找到最大位置(即最近的位置)。

    如果允许值的范围相当小,一种简单的方法是使用一系列数组,其中A [k] [x]存储[x * 2 ^ k范围内所有元素的最大位置, (X + 1)* 2 ^ k)的

    如果值最多为M位(即值在0到2 ^ M-1范围内),则更新或访问此数据结构都是O(M)操作。

    复杂性

    给定的方法是O(nM + k)。

    如果值的范围较大,则可以使用二叉搜索树的形式而不是一系列数组,或者对值进行排序并将值替换为其序数值。这将具有复杂度O(nlogn + k)。

    计算三项

    如果您只想知道此表单的三元组总数,那么您可以在O(n)中执行此操作。

    这个想法与以前类似:

    1. 查找每个索引的最新较小元素,以及每个索引的较小元素数
    2. 为每个索引查找下一个更大的元素,以及更多元素的计数
    3. 计算每个索引的较小元素数和较大元素数的乘积之和。
    4. 为了使这个O(n)我们需要能够在O(n)中找到下一个更大的元素。这可以通过以下方式完成:

      1. 将当前索引i推送到堆栈
      2. 而A [top(stack)]&lt; A [i + 1],从堆栈弹出索引x并存储NGE [x] = i + 1
      3. 递增i并返回步骤1
      4. 我们还需要能够在O(n)中找到更多元素的数量。一旦准备好NGE阵列,我们就可以通过在阵列上向后迭代并计算

        来找到计数
        count_greater_elements[i] = count_greater_elements[ NGE[i] ] + 1 if NGE[i] is defined
                                  = 0 otherwise
        

        最近的较小元素和计数可以用类似的方式计算。

答案 2 :(得分:2)

一般情况的N ^ 2解决方案(计算所有这样的三元组,不输出全部;输出将仅因为它的大小而取n ^ 3):

对于数组中的每个数字X,使用小于x的索引计算小于X的数字,使用大于X的索引计算大于X的数字。对于每个X,我们可以获得三元组的数量,其中X是中间元素就像[X] *更大[X]一样。答案是这些产品的总和。

int calc(vector<int> numbers) {
 int n = numbers.size();
 vector<int> less(n), more(n);
 for (int i = 0; i < n; i++)
  for (int j = i + 1; j < n; j++)
   if (numbers[i] < numbers[j])
    less[j]++, more[i]++;

 int res = 0;
 for (int i = 0; i < n; i++)
  res += less[i] * more[i];

 return res;
}