【问题标题】:How to find 3 numbers in increasing order and increasing indices in an array in linear time如何在线性时间内按递增顺序查找 3 个数字并在数组中递增索引
【发布时间】:2012-04-17 23:36:50
【问题描述】:

我在一个网站上遇到了这个问题。正如那里提到的,这是在亚马逊采访中被问到的。在给定的约束条件下,我无法找到合适的解决方案。

给定一个 n 整数数组,在 O(n) 时间内找到 3 个元素,使得 a[i] < a[j] < a[k]i < j < k

【问题讨论】:

  • 那么,你尝试了什么?
  • @HenkHolterman 我的想法将我带到了与以下 twall 方法类似的方向。但最后我最终发现了自己解决方案中的错误...... :(

标签: arrays c algorithm time-complexity


【解决方案1】:

以下是解决问题的方法。您需要对数组进行三次迭代。在第一次迭代中,将所有大于它们的元素标记在右侧,在第二次迭代中,将所有小于它们的元素标记在左侧。现在你的答案将是一个同时具有这两者的元素:

int greater_on_right[SIZE];
int smaller_on_left[SIZE];
memset(greater_on_rigth, -1, sizeof(greater_on_right));
memset(smaller_on_left, -1, sizeof(greater_on_right));

int n; // number of elements;
int a[n]; // actual elements;
int greatest_value_so_far = a[n- 1];
int greatest_index = n- 1;
for (int i = n -2; i >= 0; --i) {
   if (greatest_value_so_far > a[i]) {
     greater_on_right[i] = greatest_index;
   } else {
     greatest_value_so_far = a[i];
     greatest_index = i;
   }
}

// Do the same on the left with smaller values


for (int i =0;i<n;++i) {
  if (greater_on_right[i] != -1 && smaller_on_left[i] != -1) {
    cout << "Indices:" << smaller_on_left[i] << ", " << i << ", " << greater_on_right[i] << endl;
  }
}

此解决方案在整个数组上迭代 3 次,因此是线性的。我没有提供完整的解决方案,所以你可以在左边训练自己,看看你是否明白我的想法。很抱歉没有给出一些提示,但我不知道如何给出提示而不显示实际的解决方案。

希望这能解决您的问题。

【讨论】:

  • 好主意!我承认,我的做法有很多缺陷,我应该从更广泛的意义上思考:线性并不意味着一次迭代,即使我很确定它是可行的。我稍后会尝试找到解决方案!
  • 如果我错了,请纠正我,但如果输入是 {1,2,3,4} 你找不到所有的三元组,即 [1,2,3][1,2 ,4][1,3,4][2,3,4]
  • @daniele 您只需要找到 一个 三元组,而不是全部。您不能期望能够在线性时间内打印所有三元组,因为它们的数量可能是立方的。
  • @devsnd:我发现(没想到自己)一个只使用 O(1) 状态(4 个变量)的一次性解决方案。我将其发布为答案,并在编程挑战网站上提供了指向原作者的链接。我一直认为您需要跟踪许多潜在的回溯候选人,但事实证明您不必这样做。
  • @Vivek 请再次阅读问题。 OP 要求算法找到一个三元组,而不是全部。顺便说一句,我的代码都可以很容易地找到最左边的代码
【解决方案2】:

一次性线性时间,具有 O(1) 额外空间(4 个变量)。非常高效(每次迭代只有几个比较/分支,并且没有太多的数据混洗)。

不是我最初的想法或算法,我只是整理了一下并评论了the code in an ideone fork。您可以在那里向代码添加新的测试用例并在线运行。 originalKenneth, posted in comments on a thread on www.geeksforgeeks.org。很棒的算法,但最初的实现在实际循环之外有一些非常愚蠢的代码。 (例如,代替局部变量,让我们在一个类中使用两个成员变量,并将该函数实现为class Solution 的成员函数......变量名很烂。我选择了非常冗长的。)

Kenneth,如果您想发布您的代码作为答案,请继续。我不是想窃取算法的功劳。 (不过,我确实在编写这个解释方面做了一些工作,并思考了为什么它有效。)

讨论线程上方的主要文章与 Ivaylo Strandjev 的答案具有相同的解决方案。 (主要文章的代码是 Pramod 作为对这个问题的答案发布的,在 Ivalyo 的回答几个月后。这就是我在 cmets 中找到有趣答案的方式。)


由于您只需要找到一个 解决方案,而不是全部解决方案,因此没有您期望的那么多极端案例。事实证明,如果你选择了正确的东西作为状态,你不需要跟踪你看到的每一个可能的开始和中间值,甚至根本不需要回溯。


主要技巧有:

  • 单调递减值序列中的最后一个值是您唯一需要考虑的值。这适用于第一(低)和第二(中)候选元素。

  • 任何时候你看到一个较小的候选中间元素,你可以从那里重新开始,只是寻找最终元素或更好的中间候选。

    如果您在小于当前中间候选人的元素之前还没有找到由 3 个递增元素组成的序列,那么 min-so-far 和新的较小中间候选人同样好(宽容、灵活)你可以用你已经检查过的数字来做。 (请参阅代码中的 cmets 以获得更好的表述方式。)

    其他几个答案犯了一个错误,即每次看到新的最小或最大元素而不是中间元素时都重新开始。您跟踪您看到的当前最小值,但在看到新中间之前您不会做出反应或使用它。

要找到新的候选中间元素,请检查它们是否小于当前的中间候选元素,以及到目前为止看到的 != min 元素。

我不确定这个想法是否可以依次扩展到 4 个或更多值。寻找新的候选 3rd 值可能需要将当前候选第二和第三之间的最小值与总最小值分开跟踪。这可能会变得棘手,并且需要更多的条件。但是如果它可以在恒定大小的状态下正确完成并且一次通过而不回溯,它仍然是线性时间。

// Original had this great algorithm, but a clumsy and weird implementation (esp. the code outside the loop itself)

#include <iostream>
#include <vector>

using namespace std;

//Find a sorted subsequence of size 3 in one pass, linear time
//returns an empty list on not-found
vector<int> find3IncreasingNumbers(int * arr, int n)
{
    int min_so_far = arr[0];
    int c_low, c_mid;            // candidates
    bool have_candidates = false;

    for(int i = 1; i < n; ++i)  {
        if(arr[i] <= min_so_far)  // less-or-equal prevents values == min from ending up as mid candidates, without a separate else if()continue;
            min_so_far = arr[i];
        else if(!have_candidates || arr[i] <= c_mid) {
            // If any sequence exists with a middle-numbers we've already seen (and that we haven't already finished)
            // then one exists involving these candidates
            c_low = min_so_far;
            c_mid = arr[i];
            have_candidates = true;
        } else {
            // have candidates and arr[i] > c_mid
            return vector<int> ( { c_low, c_mid, arr[i] } );
        }
    }

    return vector<int>();  // not-found
}

int main()
{
    int array_num = 1;

// The code in this macro was in the original I forked.  I just put it in a macro.  Starting from scratch, I might make it a function.
#define TRYFIND(...) do { \
        int arr[] = __VA_ARGS__ ; \
        vector<int> resultTriple = find3IncreasingNumbers(arr, sizeof(arr)/sizeof(arr[0])); \
        if(resultTriple.size()) \
            cout<<"Result of arr" << array_num << ": " <<resultTriple[0]<<" "<<resultTriple[1]<<" "<<resultTriple[2]<<endl; \
        else \
            cout << "Did not find increasing triple in arr" << array_num << "." <<endl; \
        array_num++; \
    }while(0)

    TRYFIND( {12, 11, 10, 5, 6, 2, 30} );
    TRYFIND( {1, 2, 3, 4} );
    TRYFIND( {4, 3, 1, 2} );
    TRYFIND( {12, 1, 11, 10, 5, 4, 3} );
    TRYFIND( {12, 1, 11, 10, 5, 4, 7} );
    TRYFIND( {12, 11, 10, 5, 2, 4, 1, 3} );
    TRYFIND( {12, 11, 10, 5, 2, 4, 1, 6} );
    TRYFIND( {5,13,6,10,3,7,2} );
    TRYFIND( {1, 5, 1, 5, 2, 2, 5} );
    TRYFIND( {1, 5, 1, 5, 2, 1, 5} );
    TRYFIND( {2, 3, 1, 4} );
    TRYFIND( {3, 1, 2, 4} );
    TRYFIND( {2, 4} );

    return 0;
}

制作一个可以将初始化列表作为参数的 CPP 宏很难看:
Is it possible to pass a brace-enclosed initializer as a macro parameter?

尽管如此,无需在 4 个地方编辑 arr4arr5 即可轻松添加新的测试用例,这是非常值得的。

【讨论】:

    【解决方案3】:

    我发布了另一种解决方法here

    #include<stdio.h>
    
    // A function to fund a sorted subsequence of size 3
    void find3Numbers(int arr[], int n)
    {
       int max = n-1; //Index of maximum element from right side
       int min = 0; //Index of minimum element from left side
       int i;
    
       // Create an array that will store index of a smaller
       // element on left side. If there is no smaller element
       // on left side, then smaller[i] will be -1.
       int *smaller = new int[n];
       smaller[0] = -1;  // first entry will always be -1
       for (i = 1; i < n; i++)
       {
           if (arr[i] < arr[min])
           {
              min = i;
              smaller[i] = -1;
           }
           else
              smaller[i] = min;
       }
    
       // Create another array that will store index of a
       // greater element on right side. If there is no greater
       // element on right side, then greater[i] will be -1.
       int *greater = new int[n];
       greater[n-1] = -1;  // last entry will always be -1
       for (i = n-2; i >= 0; i--)
       {
           if (arr[i] > arr[max])
           {
              max = i;
              greater[i] = -1;
           }
           else
              greater[i] = max;
       }
    
       // Now find a number which has both a greater number on
       // right side and smaller number on left side
       for (i = 0; i < n; i++)
       {
           if (smaller[i] != -1 && greater[i] != -1)
           {
              printf("%d %d %d", arr[smaller[i]],
                     arr[i], arr[greater[i]]);
              return;
           }
       }
    
       // If we reach number, then there are no such 3 numbers
       printf("No such triplet found");
       return;
    }
    
    // Driver program to test above function
    int main()
    {
        int arr[] = {12, 11, 10, 5, 6, 2, 30};
        int n = sizeof(arr)/sizeof(arr[0]);
        find3Numbers(arr, n);
        return 0;
    }
    

    【讨论】:

    • 与@Ivaylo Strandjev 给出的解决方案完全相同。
    • 该链接指向一个编程挑战网站,许多解决方案都在 cmets 中发布。
    【解决方案4】:

    只是为了好玩: 在 JAVA 中:

    List<Integer> OrderedNumbers(int[] nums){
        List<Integer> res = new LinkedList<>();
        int n = nums.length;
        //if less then 3 elements, return the empty list
        if(n<3) return res;
    
        //run 1 forloop to determine local min and local max for each index
        int[] lMin = new int[n], lMax = new int[n];
        lMin[0] = nums[0]; lMax[n-1] = nums[n-1];
        for(int i=1; i<n-1; i++){
            lMin[i] = Math.min(lMin[i-1], nums[i]);
            lMax[n-i-1] = Math.max(lMax[n-i],nums[n-i-1]);
        }
    
        //if a condition is met where min(which always comes before nums[i] and max) < nums[i] < max, add to result set and return;
        for(int i=1; i<n-1; i++){
            if(lMin[i]<nums[i] && nums[i]<lMax[i]){
                res.add(lMin[i]);
                res.add(nums[i]);
                res.add(lMax[i]);
                return res;
            }
        }
        return res;
    }
    

    【讨论】:

      【解决方案5】:

      这个问题与计算最长递增子序列非常相似,其约束条件是该子序列的大小必须等于 3。 LIS 问题(使用 O(nlog(n)) 解决方案)可以很容易地针对这个特定问题进行修改。此解决方案具有 O(n) 单程复杂度和 O(1) 空间。

      此解决方案要求列表中仅出现唯一元素。我们使用online solution。当我们遇到任何新元素时,它都有可能扩展当前最优化的子序列或开始一个新的子序列。在这种情况下,由于递增子序列的最大长度为 3,因此当前正在处理的任何新元素都可以将大小为 2 到 3 和 1 到 2 的序列扩展。因此我们维护包含最优化元素的活动列表。

      在这个特定问题中,我们必须维护的最大活动列表数是 2 - 一个大小为 2,另一个大小为 1。一旦我们找到大小为 3 的列表,我们就会得到答案。我们确保每个活动列表以最小数量终止。有关此想法的更详细说明,请参阅this

      在线解决方案中的任何时间点,这两个活动列表将存储列表中最有效的值 - 列表的末尾将是可以放置在那里的最小元素。假设这两个列表是:

      大小 2 列表 => [a,b]

      大小 1 列表 => [c]

      初始列表很容易编写(参考下面的代码)。假设下一个要输入的数字是d。那么情况(执行中的级联)如下:

      案例 1:d &gt; b。 在这种情况下,我们有我们的答案,a &lt; b &lt; d

      案例 2:b &gt; d &gt; a。在这种情况下,大小为 2 的列表可以通过以d 而不是b 来最佳表示,因为在d 之后出现的每个元素都大于b 也将大于d。所以我们将 b 替换为 d。

      案例 3:d &lt; c。由于案例 1 和 2 失败,它自动暗示 d &lt; a。在这种情况下,它可能会启动一个大小为 1 的新列表。比较大小为 1 的列表以获得最有效的活动列表。如果这种情况属实,我们将c 替换为d

      案例 4:Otherwise。这种情况意味着d &lt; bc &lt; d。在这种情况下,大小为 2 的列表效率低下。所以我们用[c, d]替换[a, b]

      #include <bits/stdc++.h>
      using namespace std;
      
      class Solution {
      public:
          int two_size_first;
          int two_size_mid;
          int one_size;
          int end_index;
          vector<int> arr;
      
          Solution(int size) {
              end_index = two_size_mid = two_size_first = one_size = -1;
              int temp;
              for(int i=0; i<size; i++) {
                  cin >> temp;
                  arr.push_back(temp);
              }   
          }
      
          void solve() {
              if (arr.size() < 3)
                  return;
      
              one_size = two_size_first = arr[0];
              two_size_mid = INT_MAX;
      
              for(int i=1; i<arr.size(); i++) {
                  if(arr[i] > two_size_mid) {
                      end_index = i;
                      return;
                  }
                  else if (two_size_first < arr[i] && arr[i] < two_size_mid) {
                      two_size_mid = arr[i];
                  }
                  else if (one_size > arr[i]) {
                      one_size = arr[i];
                  }
                  else {
                      two_size_first = one_size;
                      two_size_mid = arr[i];
                  }
              }
          }
      
          void result() {
              if (end_index != -1) {
                  cout << two_size_first << " " << two_size_mid << " " << arr[end_index] << endl; 
              }
              else {
                  cout << "No such sequence found" << endl;
              }
          }
      };
      
      int main(int argc, char const *argv[])
      {
          int size;
          cout << "Enter size" << endl;
          cin >> size;
          cout << "Enter "  << size << " array elements" << endl;
          Solution solution(size);
      
          solution.solve();
          solution.result();
          return 0;
      }
      

      【讨论】:

      • 这个想法也可以用来寻找大小大于3的递增子序列。
      【解决方案6】:

      我的方法 - O(N) 时间两次通过 O(1) 空间并使用两个变量

      对于我们访问的数组的每个元素,我们保持其左侧的最小值以检查该元素是否可能是中间元素,并记录其左侧的最小中间元素以检查该元素是否可能是候选第三个元素,或者它可能形成一个中间元素,其值低于目前找到的值。将 min so far 和 middle so far 初始化为 INT_MAX,

      因此我们必须检查每个元素:

      如果一个特定的数组元素大于到目前为止的中间元素的最小值,那么这个数组元素的答案就是 thi 作为第三个元素,最小的中间元素作为中间元素(我们将不得不搜索第三个元素然后通过一次)

      Else 如果一个特定的数组元素大于最小值,则该元素可能是候选中间元素,现在我们必须检查候选中间元素是否小于当前中间元素,如果是则更新当前中间元素

      ELSE 如果特定数组元素小于迄今为止的最小值,则使用 arr[i] 更新迄今为止的最小值。

      因此,对于我们访问的数组的每个元素,我们保持其左侧的最小值以检查该元素是否可能是中间元素,并记录其左侧的最小中间元素以检查该元素是否可能是候选的第三个元素,也可能是一个中间元素,其值低于目前找到的值。
      #包括 使用命名空间标准;

      int main()
      {
      int i,j,k,n;
      cin >> n;
      int arr[n];
      for(i = 0;i < n;++i)
          cin >> arr[i];
      int m = INT_MAX,sm = INT_MAX,smi;// m => minimum so far found to left
      for(i = 0;i < n;++i)// sm => smallest middle element found so far to left
      {
          if(arr[i]>sm){break;}// This is the answer
          else if(arr[i] < m ){m = arr[i];}
          else if(arr[i] > m){if(arr[i]<sm){sm = arr[i];smi = i;}}
          else {;}
      }
      if((i < n)&&(arr[i]>sm))
      {
          for(j = 0;j < smi;++j){if(arr[j] < sm){cout << arr[j] << " ";break;}}
          cout << sm << " " << arr[i]<< endl;
      }
      else 
          cout << "Such Pairs Do Not Exist" << endl;
      return 0;
      }
      

      【讨论】:

        【解决方案7】:

        这是我的 O(n) 解决方案,空间复杂度为 O(1):- 只是一个返回由三个值组成的向量的函数(如果是 exixts)

        `vector<int> find3Numbers(vector<int> A, int N)
         {
            int first=INT_MAX,second=INT_MAX,third=INT_MAX,i,temp=-1;
            vector<int> ans;
            for(i=0;i<N;i++)
            {
                if(first!=INT_MAX&&second!=INT_MAX&&third!=INT_MAX)
                {
                    ans.push_back(first);
                    ans.push_back(second);
                    ans.push_back(third);
                    return ans;
                }
                if(A[i]<=first)
                {
                    if(second!=INT_MAX)
                    {
                        if(temp==-1)
                        {
                            temp=first;
                        }
                        first=A[i];
                    }
                    else
                    {
                        first=A[i];
                    }
                }
                else if(A[i]<=second)
                {
                    second=A[i];
                    temp=-1;
                }
                else
                {
                    if(temp!=-1)
                    {
                        first=temp;
                    }
                    third=A[i];
                }
            }
            if(first!=INT_MAX&&second!=INT_MAX&&third!=INT_MAX)
            {
                ans.push_back(first);
                ans.push_back(second);
                ans.push_back(third);
                return ans;
            }
            return ans;
        }`
        

        【讨论】:

          【解决方案8】:

          这是这个问题的 O(n) 时间和 O(1) 空间复杂度的解决方案

          bool increasingTriplet(vector<int>& a) {
          
              int i,n=a.size(),first=INT_MAX,second=INT_MAX;
              if(n<3)
                  return false;
          
              for(i=0;i<n;i++)
              {
                  if(a[i]<=first)
                      first = a[i];
                  else if(a[i]<=second)
                      second = a[i];
                  else
                      return true;
              }
              return false;
          }
          
          

          如果数组中存在一对按升序排序的 3 个元素,则此函数返回 true。 您还可以修改此函数以打印所有 3 个元素或其索引。只需更新它们的索引以及变量 first 和 second。

          【讨论】:

            【解决方案9】:

            下面是我的解决方案。

            public boolean increasingTriplet(int[] nums) {
            
                int min1 = Integer.MAX_VALUE;
                int min2 = Integer.MAX_VALUE;
            
                for (int i =0; i<nums.length; i++) {
                    if (nums[i]<min1) {
                        min1 = nums[i];
                    } else if (nums[i]<min2 && nums[i]>min1) {
                        min2=nums[i];
                    } else if (nums[i]>min2) {
                        return true;
                    }
                }
                return false;
            }
            

            【讨论】:

              【解决方案10】:

              尝试创建两个变量:

              1. index_sequence_length_1 = index i such
                 a[i] is minimal number
              2. index_sequence_length_2 = index j such
                 There is index i < j such that a[i] < a[j] and a[j] is minimal
              

              遍历整个数组并在每次迭代中更新此变量。

              如果您遍历大于 a[index_sequence_length_2] 的元素,则您会找到您的序列。

              【讨论】:

              • 我认为描述不完整!很多案例都没有考虑到,而且这种方法也没有导致正确的解决方案。
              • 是的,这将整体最小元素视为序列开始的唯一候选。在 2 3 1 4 上失败。第一遍之后,i指向1,j指向4
              【解决方案11】:

              对不起,我忍不住想解开这个谜题…… 这是我的解决方案。

              //array indices
              int i, j, k = -1;
              //values at those indices
              int iv, jv, kv = 0;
              for(int l=0; l<a.length(); l++){
                  //if there is a value greater than the biggest value
                  //shift all values from k to i
                  if(a[l]>kv || j == -1 || i == -1){
                      i = j;
                      iv = jv;
                      j = k;
                      jv = kv
                      kv = a[l]
                      k = l
                  }
                  if(iv < jv && jv < kv && i < j && j < k){
                      break;
                  }    
              }
              

              【讨论】:

              • +1。好的。 :) 虽然我不会使用 iv、jv 和 kv,但我想这样更有效,所以我不能抱怨。你怎么知道你找到了它?检查i != j &amp;&amp; j != k.
              • 这是做什么的?对于输入“100, 1,2,3”,您将只设置 kv = 100 就是这样,而有一组有效的三个数字。
              • 我更新了答案,感谢 izomorphius 和 Neil 的输入
              • 好的,现在你会为输入“1001,100,200,1,2,3”做什么?我不认为你的方法是正确的方向。
              • 当新的高于 kv 的值不是序列的一部分时,它会失败。它在1 5 2 3 上失败(因为班次下降了 1 而不是 5)。我认为即使修复这个错误仍然会留下一个可能遗漏东西的算法,因为它不能回溯以考虑以它忽略的值开头的序列小于它在寻找两个之后的第三个增加值时所具有的kv其他候选人。 (不幸的是,这个想法存在根本缺陷。)
              【解决方案12】:

              迭代一次就完成了:

              public static int[] orderedHash(int[] A){
                  int low=0, mid=1, high=2;
                  for(int i=3; i<A.length; i++){
                      if(A[high]>A[mid] && A[mid]>A[low])
                          break;
              
                      if(A[low]>A[i])
                          low=mid=high=i;
                      else if(low == mid && mid == high)
                          mid = high = i;
                      else if(mid == high){
                          if(A[high]<A[i])
                              high = i;
                          else
                              mid = high = i;
                      }
                      else if(A[mid]<A[i])
                          high = i;
                      else if( A[high]<A[i]){
                          mid = high;
                          high =i;
                      }
                      else
                          mid=high=i;
                  }
                  return new int[]{A[low],A[mid],A[high]};
              }//
              

              然后用 main 测试:

              public static void main(String[] args) {
                  int[][] D = {{1, 5, 5, 3, 2, 10},
                      {1, 5, 5, 6, 2, 10},
                      {1, 10, 5, 3, 2, 6, 12},
                      {1, 10, 5, 6, 8, 12, 1},
                      {1, 10, 5, 12, 1, 2, 3, 40},
                      {10, 10, 10, 3, 4, 5, 7, 9}};
                  for (int[] E : D) {
                      System.out.format("%s GIVES %s%n", Arrays.toString(E), Arrays.toString(orderedHash(E)));
                  }
              }
              

              【讨论】:

              • 感谢您的回复,但编写算法以更好地理解他人而不是仅仅轰炸您的代码总是好的。即使你这样做,也应该得到很好的评论。 :) 如果这个想法不能在算法中很好地表达,欢迎使用代码......
              • 这只是一个 for 循环和一些 if-else,所以我认为这很容易理解。有什么不明白的细节吗?我很乐意提供帮助。
              • 现在我查看了您的代码,恐怕它不会产生正确的结果!试试这个测试用例:3,10,5,1,11
              • 优秀的 cmets 会说一些关于维护哪些不变量以及算法如何处理任务的信息。阅读它而不是在脑海中追踪代码会快得多
              • 这个算法会被新的最小元素分散注意力(因为它每次发现小于A[low]的元素时都会以low=mid=high=i重新启动)。出于这个原因,我很确定它在3 4 1 5 上失败了。只有忽略第一个单调递减元素序列才是安全的。
              【解决方案13】:

              如果你构建一个最大堆 O(n) 然后提取最大 O(1) 3 次怎么办?

              【讨论】:

              • 它不满足提到的约束!!此外,您需要检查您提到的复杂性... :)
              【解决方案14】:

              这是一个只有一次迭代的解决方案。

              我正在使用堆栈为每个索引 k 计算是否存在其他两个索引 i 和 j 使得 a[i]

              bool f(vector<int> a) {
              
                  int n = a.size();
                  stack<int> s;
                  for (int i = 0; i < n; ++i)
                  {
                      while(!s.empty() and a[s.top()]>=a[i]){
                          s.pop();
                      }
              
                      if (s.size()>=2) // s.size()>=k-1
                      {
                          return 1;
                      }
                      s.push(i);
              
                  }
              
                  return 0;
              }
              

              重要的是,在一般情况下,我们可以将此问题扩展到 M 个这样的索引,而不是 k 个索引。

              【讨论】:

              • 大家好,这个解决方案有什么限制吗?
              • @greybeard,它会返回 true,因为 2,3,4 就是这样的三元组之一。代码更正。如果您在 push() 之前检查堆栈大小,我们可能会错过一个可能的三元组。例如对于 1,2,3,在这种情况下我们将返回 0。
              • @greybeard,是的,你是对的。我之前误解了,但是这种优化只会将空间复杂度降低 O(1)。无论如何,通常空间复杂度是 O(k)。对于这个问题,它的恒定空间和一次通过过程(在最坏的情况下实际上是 2*n 步骤)。显然,这比以前更好。步数和精确的空间复杂度。
              • (问题运行find 3 elements 没有用黑白拼写成功后该怎么做,更不用说失败了。堆叠值的工作方式与拥有数组和堆叠索引相同,因此a(部分正确,取决于机器型号)恒定空间在线算法。)
              • (真可惜。我之前删除了关于信心的评论并没有帮助……)2、3、1、4呢?
              猜你喜欢
              • 2019-06-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-11-05
              • 1970-01-01
              • 2016-10-26
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多