程式設計之美6:陣列迴圈移位
樓主又來~(≧▽≦)/~啦啦啦,科研,就是要這麼一鼓作氣。額,其實樓主的老本行是推公式啊,做這些演算法題,其實是樓主在偷懶。額,話不多說了,快請出我們今天的主角吧!還是關於陣列的-陣列迴圈移位。
下面我們來看下題目的要求。
題目要求:
設計一個演算法,把一個含有N個元素的陣列迴圈右移K位,要求時間複雜度為
題目解答
我們來自己給個例子,來幫助自己思考。如陣列為[1, 2, 3, 4, 5, 6, 7, 8],迴圈移位4次。
原始序列:[1, 2, 3, 4, 5, 6, 7, 8]
右移1位:[8, 1, 2, 3, 4, 5, 6, 7]
右移2位:[7, 8, 1, 2, 3, 4, 5, 6]
右移3位:[6, 7, 8, 1, 2, 3, 4, 5]
右移4位:[5, 6, 7, 8, 1, 2, 3, 4]
解法一:時間複雜度O(N * K)
程式碼:
#include <iostream>
#include <vector>
using namespace std;
void getShiftArray (int *pArray, int len, int K);
void printArray(int *pArray, int len);
int main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
int len = sizeof(a) / sizeof(int);
int K = 4 ;
getShiftArray(a, len, K);
printArray(a, len);
system("pause");
}
void getShiftArray (int *pArray, int len, int K)
{
int endTemp = 0;
while (K--)
{
endTemp = pArray[len - 1]; //儲存陣列最後一個元素
for (int n = len - 1; n >= 0; n--)
{
pArray[n] = pArray[n - 1 ];
}
pArray[0] = endTemp;
}
}
void printArray(int *pArray, int len)
{
for (int i = 0; i < len; i++)
{
cout << pArray[i] << " ";
}
cout << endl;
}
這種解法是不符合題目的線性複雜度要求的。
但是我們在這兒會意識到一個問題,如果K > N怎麼辦呢?我們可以試驗一下,一個數組迴圈移位N次,陣列會回到原始的樣子。那麼當K> N時,只需要向右迴圈移位K - N次就好了。綜合一下,無論K取什麼值,那麼都只需要向右迴圈移位K % N次,那麼上面的程式碼只需要改動一點點,時間複雜度就可以變為
#include <iostream>
#include <vector>
using namespace std;
void getShiftArray (int *pArray, int len, int K);
void printArray(int *pArray, int len);
int main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
int len = sizeof(a) / sizeof(int);
int K = 12;
getShiftArray(a, len, K);
printArray(a, len);
system("pause");
}
void getShiftArray (int *pArray, int len, int K)
{
int endTemp = 0;
K = K % len;
while (K--)
{
endTemp = pArray[len - 1]; //儲存陣列最後一個元素
for (int n = len - 1; n >= 0; n--)
{
pArray[n] = pArray[n - 1];
}
pArray[0] = endTemp;
}
}
void printArray(int *pArray, int len)
{
for (int i = 0; i < len; i++)
{
cout << pArray[i] << " ";
}
cout << endl;
}
解法二:線性時間
其實,細心發現一下就看出來了,[1, 2, 3, 4, 5, 6, 7, 8]可以分為兩部分,不加粗的為第一部分,加粗的是第二部分。如果這個陣列向右迴圈移位4次的話,其實兩部分的內部順序都是不變的,只是兩個部分交換一下就好了。那麼我們可以按照下面的流程來完成迴圈移位(靠,真是大神,怎麼想出來的?)。
原始序列:[1, 2, 3, 4, 5, 6, 7, 8]
將前半部分逆序:[4, 3, 2, 1, 5, 6, 7, 8]
將後半部分逆序:[4, 3, 2, 1, 8, 7, 6, 5]
將整個序列逆序:[5, 6, 7, 8,1, 2, 3, 4 ]
看程式碼,是如此的簡單。
#include <iostream>
#include <vector>
using namespace std;
void getShiftArray (int *pArray, int len, int K);
void printArray(int *pArray, int len);
void reverseArray(int *pArray, int start, int end);
int main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
int len = sizeof(a) / sizeof(int);
int K = 12;
getShiftArray(a, len, K);
printArray(a, len);
system("pause");
}
void getShiftArray (int *pArray, int len, int K)
{
K = K % len;
//前半部分逆序
reverseArray(pArray, 0, len - K - 1);
//後半部分逆序
reverseArray(pArray, len - K, len - 1);
//整個序列逆序
reverseArray(pArray, 0, len - 1);
}
void reverseArray(int *pArray, int start, int end)
{
for (; start < end; start++, end--)
swap(pArray[start], pArray[end]);
}
void printArray(int *pArray, int len)
{
for (int i = 0; i < len; i++)
{
cout << pArray[i] << " ";
}
cout << endl;
}
哈哈哈哈,有沒有明白呢?樓主申請專欄去啦!如果你也想學習演算法,那麼可以和樓主一起抱團啊,多多交流,加油加油↖(^ω^)↗