How to tell if an array is a permutation in O(n)?

后端 未结 16 1673
粉色の甜心
粉色の甜心 2020-12-07 10:17

Input: A read-only array of N elements containing integer values from 1 to N (some integer values can appear more than once!). And a memory zone of a fixed<

16条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-07 10:23

    Check out the following solution. It uses O(1) additional space. It alters the array during the checking process, but returns it back to its initial state at the end.

    The idea is:

    1. Check if any of the elements is out of the range [1, n] => O(n).
    2. Go over the numbers in order (all of them are now assured to be in the range [1, n]), and for each number x (e.g. 3):

      • go to the x'th cell (e.g. a[3]), if it's negative, then someone already visited it before you => Not permutation. Otherwise (a[3] is positive), multiply it by -1. => O(n).
    3. Go over the array and negate all negative numbers.

    This way, we know for sure that all elements are in the range [1, n], and that there are no duplicates => The array is a permutation.

    int is_permutation_linear(int a[], int n) {
        int i, is_permutation = 1;
    
        // Step 1.
        for (i = 0; i < n; ++i) {
            if (a[i] < 1 || a[i] > n) {
                return 0;
            }
        }
    
        // Step 2.
        for (i = 0; i < n; ++i) {
            if (a[abs(a[i]) - 1] < 0) {
                is_permutation = 0;
                break;
            }
            a[i] *= -1;
        }
    
        // Step 3.
        for (i = 0; i < n; ++i) {
            if (a[i] < 0) {
                a[i] *= -1;
            }
        }
    
        return is_permutation;
    }
    

    Here is the complete program that tests it:

    /*
     * is_permutation_linear.c
     *
     *  Created on: Dec 27, 2011
     *      Author: Anis
     */
    
    #include 
    
    int abs(int x) {
        return x >= 0 ? x : -x;
    }
    
    int is_permutation_linear(int a[], int n) {
        int i, is_permutation = 1;
    
        for (i = 0; i < n; ++i) {
            if (a[i] < 1 || a[i] > n) {
                return 0;
            }
        }
    
        for (i = 0; i < n; ++i) {
            if (a[abs(a[i]) - 1] < 0) {
                is_permutation = 0;
                break;
            }
            a[abs(a[i]) - 1] *= -1;
        }
    
        for (i = 0; i < n; ++i) {
            if (a[i] < 0) {
                a[i] *= -1;
            }
        }
    
        return is_permutation;
    }
    
    void print_array(int a[], int n) {
        int i;
        for (i = 0; i < n; i++) {
            printf("%2d ", a[i]);
        }
    }
    
    int main() {
        int arrays[9][8] = { { 1, 2, 3, 4, 5, 6, 7, 8 },
                             { 8, 6, 7, 2, 5, 4, 1, 3 },
                             { 0, 1, 2, 3, 4, 5, 6, 7 },
                             { 1, 1, 2, 3, 4, 5, 6, 7 },
                             { 8, 7, 6, 5, 4, 3, 2, 1 },
                             { 3, 5, 1, 6, 8, 4, 7, 2 },
                             { 8, 3, 2, 1, 4, 5, 6, 7 },
                             { 1, 1, 1, 1, 1, 1, 1, 1 },
                             { 1, 8, 4, 2, 1, 3, 5, 6 } };
        int i;
    
        for (i = 0; i < 9; i++) {
            printf("array: ");
            print_array(arrays[i], 8);
            printf("is %spermutation.\n",
                   is_permutation_linear(arrays[i], 8) ? "" : "not ");
            printf("after: ");
            print_array(arrays[i], 8);
            printf("\n\n");
    
        }
    
        return 0;
    }
    

    And its output:

    array:  1  2  3  4  5  6  7  8 is permutation.
    after:  1  2  3  4  5  6  7  8 
    
    array:  8  6  7  2  5  4  1  3 is permutation.
    after:  8  6  7  2  5  4  1  3 
    
    array:  0  1  2  3  4  5  6  7 is not permutation.
    after:  0  1  2  3  4  5  6  7 
    
    array:  1  1  2  3  4  5  6  7 is not permutation.
    after:  1  1  2  3  4  5  6  7 
    
    array:  8  7  6  5  4  3  2  1 is permutation.
    after:  8  7  6  5  4  3  2  1 
    
    array:  3  5  1  6  8  4  7  2 is permutation.
    after:  3  5  1  6  8  4  7  2 
    
    array:  8  3  2  1  4  5  6  7 is permutation.
    after:  8  3  2  1  4  5  6  7 
    
    array:  1  1  1  1  1  1  1  1 is not permutation.
    after:  1  1  1  1  1  1  1  1 
    
    array:  1  8  4  2  1  3  5  6 is not permutation.
    after:  1  8  4  2  1  3  5  6 
    

提交回复
热议问题