【问题标题】:Number of contiguous subsequence连续子序列数
【发布时间】:2015-08-16 04:46:42
【问题描述】:

我需要计算长度大于 1 的连续子序列的数量,使得该子序列中的任何对的总和为 k。

如果 a = { 1 , 3 , 4 } 和 k = 4 所有 contiguos 子序列包括

{1,3} (sum of the only pair is 4)
{3,4}
{1,3,4} ( sum of one of the pair is 4 )

那么有效的子序列只有 {3,4} .. 即我的问题的答案是 1。 这里还有一个例子......

a = { 1 , 4 , 3 , 2 , 0 } k = 4; 所有子序列包括

{1,4}
{1,4,3} (sum of one pair is 4)
{1,4,3,2} (sum of one pair is 4)
{1,4,3,2,0} (sum of more than one pair is 4)
{4,3}
{4,3,2}
{4,3,2,0} (sum of one pair is 4)
{3,2)
{3,2,0}
{2,0}

以上答案有6个有效序列

我什至不知道如何开始。

【问题讨论】:

    标签: c algorithm


    【解决方案1】:

    使用 for 循环遍历数组。从数组中抓取第一项,从数组中抓取下一项,如果这两项之和等于k,则继续下一项并重复上述步骤。如果总和不等于k,则匹配。

    int x;
    for (x = 0; x < (sizeof(a) - 1); x++) {
        if ((a[x] + a[x+1]) == k) {
            // no match
        } else {
            // match
        }
    }
    

    显然,这个例子非常简单,您当然可以对此进行扩展,但这是开始的。

    【讨论】:

    • 这不是一个家庭作业问题,它更像是自学..我在其中一本教科书中找到了这个..我是一个自学者。我很抱歉,但没有得到你,你能详细说明一下吗>
    • 对不起,任何有明确问题但没有提供代码的问题都是我的作业。为自学点赞。您可以通过简单的减法轻松检查数字是否是连续的。如果差值为 1,则它是连续的。因此,您的示例中有 {3,4}。并且添加 3+4=7 不等于 4,你有一个匹配。就遍历数组而言,您可以使用索引访问项目。您可以将 1 添加到该索引,假设它是数字而不是字符串,然后检索下一个要比较的项目。
    • 按顺序是指相邻的.. 在上面的例子中 1 , 3 ,4 也是一个子序列,但它包含 1, 3 因此不是一个有效的子序列。
    • 啊抱歉,我看错了你的问题。是的,忽略顺序部分。我会更新我的答案。
    • 没关系,我更新了我的问题以减少混乱!如果问题要求不只包括 {1,3} ,那很好,但我不知道如何不包括 {1,3,4} .. 我正在尝试 O(n^2) 算法,比那更好。
    【解决方案2】:

    您需要获取长度大于一的所有间隔

    然后对子数组进行排序

    然后通过二分查找在子数组中每个元素的左右两边查找key

    java代码:

    int[] a  = {1, 4, 3, 2, 0};
        int k = 4;
        int n = a.length;
        int answer = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i + 1; j++) {
                if ((n - (i + 1)) > 0) {
                    int[] subArray = new int[n - i];
                    for (int h = j; h <= (n - (i - j + 1)); h++) {
                        subArray[h - j] = a[h];
                    }
    
                    // sort
                    Arrays.sort(subArray);
    
                    boolean exist = false;
                    for (int h = 0; h < subArray.length; h++) {
                        int key = k - subArray[h];
                        // look for key in left side [0, h)
                        int index1 = Arrays.binarySearch(subArray, 0, h, key);
                        // look for key in right side [h+1, subArray.length)
                        int index2 = Arrays.binarySearch(subArray, h + 1, subArray.length, key);
                        if (index1 >= 0 || index2 >= 0) {
                            exist = true;
                            break;
                        }
                    }
                    answer = !exist ? answer + 1 : answer;
                }
            }
        }
        System.out.println(answer);
    

    输出:

    6

    【讨论】:

      【解决方案3】:

      你可以从背面遍历数组。

      例如:

      数组是

      1 , 2 , 3 ,1

      在每个点 i ,我们将尝试计算从 i 开始的总和为 K 的子数组。

      让我们保留另一个数组,它告诉我们右侧索引 j 的最小 leftmost_Right_End 使得存在位置 e
      (i

      现在每当我们在位置 i 时,子数组从第 i 个元素开始 应该包含一对,这对可能是由于第 i 个元素或右边的某个元素而形成的!

      注意:如果我们找到任何对的最小索引使得 A[x]+A[y]== K 所有其他 z> y 对我们来说都是浪费的,因为条件说不应该存在这样的对 A[ x]+A[y]==K!

      因此问题简化为查找 K-A[i] 的每个元素 i 索引(如果存在),并从 leftmost_Right_End 获取该索引的最小值。 现在这个索引表示如果子数组从 i 开始,那么它应该至少延伸到找到索引! 所以与i相关的子数组是(N-i+1)

      现在从 N*(N-1)/2 中减去结果

      我有一个代码,我可以更好地解释,但自学需要提示而不是解决方案:)。附言: 我也是自学者!

      【讨论】:

        【解决方案4】:

        按值对数组的值到索引映射进行排序,并使用二分搜索查找总和为k 的所有对。在interval tree 中聚合对。

        一次遍历数组一个索引。当当前段(i,j)与树中的某个区间重叠时,将(segment_length ^ 2 - segment_length) / 2添加到总计数中,减去最后一个重叠计数,并将遍历窗口重置为(i + 1, j)

        例如:

        { 1 , 4 , 3 , 2 , 0 }
        
        Sorted value-to-index map: { 0:4, 1:0, 2:3, 3:2, 4:1 }
        Interval tree stores the intervals { (0,2), (1,4) }
        

        遍历:

        { 1 , 4 , 3 , 2 , 0 }      segment      total
          ^                       (i=0, j=0)      0
        
        { 1 , 4 , 3 , 2 , 0 }      segment      total
          ^   ^                   (i=0, j=1)      0
        
        { 1 , 4 , 3 , 2 , 0 }      segment      total 
          ^       ^               (i=0, j=2)      0
        
        Match (0,2) => 
        Add (2^2 - 2) / 2 = 1 to the total count (no previous overlap to subtract)
        Reset window to (1,2)
        
        { 1 , 4 , 3 , 2 , 0 }      segment      total 
              ^   ^               (i=1, j=2)      1
        
        { 1 , 4 , 3 , 2 , 0 }      segment      total 
              ^       ^           (i=1, j=3)      1
        
        { 1 , 4 , 3 , 2 , 0 }      segment      total 
              ^           ^       (i=1, j=4)      1
        
        Match (1,4) => 
        Add (3^2 - 3) / 2 = 3 to the total count (no previous overlap to subtract)
        Reset window to (2,4)
        
        { 1 , 4 , 3 , 2 , 0 }      segment      total 
                  ^       ^       (i=2, j=4)      4
        

        由于窗口跨越数组的其余部分并且与树没有重叠,我们可以添加最后一段减去之前的重叠:

        Add (3^2 - 3) / 2 - (2^2 - 2) / 2 = 2 to the total count
        
        Total = 6
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-27
          • 1970-01-01
          • 2021-10-01
          相关资源
          最近更新 更多