標籤:c++ 演算法
題目:有n個整數,使前面各數順序向後移m個位置,最後m個數變成最前面m個數,寫一函數實現以上功能,在主函數中輸入n個整數和輸出調整後的n個數。
要求:最多隻讓使用一個臨時空間。
函數介面定義如下:
Int moveRight_n(int* p,int n,int m);
這道題最容易想到的方法就是迴圈移位,實現如下:
int moveRight_n(int* p, int n, int m){int nRet = 0;int* pStart = NULL;int* pEnd = NULL;int nTmp;if (p == NULL || n <= 0 || m < 0){nRet = -1;printf("param input error!\n");return nRet;}if (m > n)m %= n;int i, j;for (i = 0; i<m; ++i){nTmp = p[0];for (j = n - 1; j>0; --j){if (j + 1 == n)p[(j + 1) % n] = p[j];p[j + 1] = p[j];}p[j + 1] = nTmp;}return nRet;}
PS:使前面各數順序向後移m個位置,注意題意了,這裡不是旋轉數組,前面各數順序向後移m個位置是不能夠使用旋轉數組的高效演算法的!
所以下面的內容不適合本題意思。還是太粗心了!
這種方法效率低,但是是最基本的解法。我們還可以觀察數組移動的規律,裡面的每一個數字無論向左還是向右移動n位,都會回到原來的位置,而我們傳入的m值可能大於n值,所以這段代碼也就是處理這種情況
if(m > n)
m %= n;
我們右移m位相當於左移n-m位,利用這個我們還可以近一半提高上面基本演算法的效率。我們先求出數組長度的一半mid,如果m>mid。題目要求左移m位,我們可以右移n-m位,這樣可以減少迴圈的次數,從而提高了一些效率。
最高效的時間複雜度當然是O(n),類似於july部落格《程式員編程藝術》的旋轉字串一節。把數組分為【0...m】和【m+1,n】2部分,分別對這2段數組反轉,然後對整個數組反轉,最後就是所要求得的移位後的數組。
詳細演算法講解參見july的部落格《程式員編程藝術》第一章、左旋轉字串,裡面有詳細的講解,在這裡也向july大神致敬!
下面是實間複雜度為O(n)的演算法實現:
void Swap(int* p1, int *p2){int nTmp;nTmp = *p1;*p1 = *p2;*p2 = nTmp;}int moveRight_n(int* p, int n, int m){int nRet = 0;int* pStart = NULL;int* pEnd = NULL;if (p == NULL || n <= 0 || m < 0){nRet = -1;printf("param input error!\n");return nRet;}if (m > n)m %= n;pStart = p;pEnd = p + n - m - 1;while (pStart < pEnd){Swap(pStart, pEnd);++pStart;--pEnd;}pStart = p + n - m;pEnd = p + n - 1;while (pStart < pEnd){Swap(pStart, pEnd);++pStart;--pEnd;}pStart = p;pEnd = p + n - 1;while (pStart < pEnd){Swap(pStart, pEnd);++pStart;--pEnd;}return nRet;}