阿里巴巴面試題|完美洗牌問題


題意:給定一個降序的正數數組,要求按【最小、最大、次小、次大…】的順序重新排序。期望的時間復雜度為O(n),空間復雜度為O(1),即不能申請額外數組。例如:輸入【7,6,5,4,3,2,1】輸出【1,7,2,6,3,5,4】

分析:

首先,計算每個元素要挪到哪里感覺很簡單,目測是這樣:
1. 舊位置i < 2/n:新位置j=2 * i +1
2. 舊位置i >= 2/n: 新位置j = 2 * (n - 1 - i)

然后就是沿鏈輪換了。本例中 a[0]=7應該被移到a[1], a[1]本來的數6應該被移到a[3], a[3]本來的數4應該被移到a[6]... 最后發現,把input數組變成output數組, 需要三組輪換:
1. a[0]->a[1]->a[3]->a[6]->a[0]
2. a[2]->a[5]-a[2]
3. a[4]位置不變
完成每個輪換只需要一個額外的變量,騰出一個數組位置。因此空間復雜度O(1)。每個元素只會被挪動一次,時間復雜度O(n)。
此外還需要標記哪些元素已經被移動過了。通常另開一個數組標記會比較方便。。但是這題不允許,所以可以把每個移動過的元素都都取負作為標記,之后再還原。(也可以用其他的標記方式)

這也對應一個群論中的結論:置換可以分解成若干個不相交的輪換。

代碼

#include <stdio.h>

int trans(int len, int i) {
    if(len % 2 == 0) {
        if(i < len / 2) return i * 2 + 1;
        else return (len - i - 1) * 2;
    } else {
        if(i < len / 2) return i * 2 + 1;
        else if(i > len / 2) return (len - i - 1) * 2;
        else return len - 1;
    }
}

void swap(int *a, int *b) {
    *a ^= *b;
    *b ^= *a;
    *a ^= *b;
}

int main(void) {
    int arr[] = {7, 6, 5, 4, 3, 2, 1};

    //start
    int len = sizeof(arr) / sizeof(*arr);
    for(int i = 0; i < len; i++) {
        if(arr[i] > 0) {
            int j = i, tmp = arr[i];
            while(arr[j = trans(len, j)] > 0) {
                swap(&tmp, &arr[j]);    // 每次與前一個交換
                arr[j] = 0 - arr[j];
            }
        }
    }
    for(int i = 0; i < len; i++) {
        arr[i] = 0 - arr[i];
    }

    //print
    for(int i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
}

這個問題其實是一個經典問題,

完美洗牌問題:

玩過撲克牌的朋友都知道,在一局完了之后洗牌,洗牌人會習慣性的把整副牌大致分為兩半,兩手各拿一半對着對着交叉洗牌。

2004年,microsoft 的 Peiyush Jain 在他發表一篇名為:“A Simple In-Place Algorithm for In-Shuffle” 的論文中提出了完美洗牌算法。

什么是完美洗牌問題呢?即給定一個數組

a1,a2,a3, …, an, b1, b2, b3, ..., bn

最終把它置換成

b1, a1, b2, a2, a3, b3,…, bn, an

這個完美洗牌問題本質上與本題完全一致的,可以在O(n)內改成形式相同。



參考鏈接:

1. https://www.zhihu.com/question/50512830/answer/121386043

2. https://www.zhihu.com/question/50512830/answer/121334031

3. https://www.jianshu.com/p/9c841ad88ded


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM