Algorithm to determine if array contains n…n+m?

前端 未结 30 3210
清酒与你
清酒与你 2020-11-28 01:45

I saw this question on Reddit, and there were no positive solutions presented, and I thought it would be a perfect question to ask here. This was in a thread about interview

30条回答
  •  北荒
    北荒 (楼主)
    2020-11-28 02:09

    A C version of Kent Fredric's Ruby solution

    (to facilitate testing)

    Counter-example (for C version): {8, 33, 27, 30, 9, 2, 35, 7, 26, 32, 2, 23, 0, 13, 1, 6, 31, 3, 28, 4, 5, 18, 12, 2, 9, 14, 17, 21, 19, 22, 15, 20, 24, 11, 10, 16, 25}. Here n=0, m=35. This sequence misses 34 and has two 2.

    It is an O(m) in time and O(1) in space solution.

    Out-of-range values are easily detected in O(n) in time and O(1) in space, therefore tests are concentrated on in-range (means all values are in the valid range [n, n+m)) sequences. Otherwise {1, 34} is a counter example (for C version, sizeof(int)==4, standard binary representation of numbers).

    The main difference between C and Ruby version: << operator will rotate values in C due to a finite sizeof(int), but in Ruby numbers will grow to accomodate the result e.g.,

    Ruby: 1 << 100 # -> 1267650600228229401496703205376

    C: int n = 100; 1 << n // -> 16

    In Ruby: check_index ^= 1 << i; is equivalent to check_index.setbit(i). The same effect could be implemented in C++: vector v(m); v[i] = true;

    bool isperm_fredric(int m; int a[m], int m, int n)
    {
      /**
         O(m) in time (single pass), O(1) in space,
         no restriction on n,
         ?overflow?
         a[] may be readonly
       */
      int check_index = 0;
      int check_value = 0;
    
      int min = a[0];
      for (int i = 0; i < m; ++i) {
    
        check_index ^= 1 << i;
        check_value ^= 1 << (a[i] - n); //
    
        if (a[i] < min)
          min = a[i];
      }
      check_index <<= min - n; // min and n may differ e.g., 
                               //  {1, 1}: min=1, but n may be 0.
      return check_index == check_value;
    }
    

    Values of the above function were tested against the following code:

    bool *seen_isperm_trusted  = NULL;
    bool isperm_trusted(int m; int a[m], int m, int n)
    {
      /** O(m) in time, O(m) in space */
    
      for (int i = 0; i < m; ++i) // could be memset(s_i_t, 0, m*sizeof(*s_i_t));
        seen_isperm_trusted[i] = false;
    
      for (int i = 0; i < m; ++i) {
    
        if (a[i] < n or a[i] >= n + m)
          return false; // out of range
    
        if (seen_isperm_trusted[a[i]-n])
          return false; // duplicates
        else
          seen_isperm_trusted[a[i]-n] = true;
      }
    
      return true; // a[] is a permutation of the range: [n, n+m)
    }
    

    Input arrays are generated with:

    void backtrack(int m; int a[m], int m, int nitems)
    {
      /** generate all permutations with repetition for the range [0, m) */
      if (nitems == m) {
        (void)test_array(a, nitems, 0); // {0, 0}, {0, 1}, {1, 0}, {1, 1}
      }
      else for (int i = 0; i < m; ++i) {
          a[nitems] = i;
          backtrack(a, m, nitems + 1);
        }
    }
    

提交回复
热议问题