給定一個數組,有0,1,2三個數,把數組排好序。不能直接用sort。html
策略一:數組
簡單的思路,掃描兩次,第一次記錄0,1,2的個數,第二次重寫數組。spa
class Solution { public: void sortColors(int A[], int n) { if(n < 2) return ; int n0 = 0, n1 = 0, n2 = 0; vector<int> ans(n); for (int j = 0; j < n; j++) { if (A[j] == 0) n0++; else if (A[j] == 1) n1++; else n2++; } int i = 0; while(i < n0) {A[i] = 0;i++;} while(i < n0 + n1) {A[i] = 1;i++;} while(i < n0 + n1 + n2) {A[i] = 2;i++;} return ; } };
但,要求只掃描一次,常數空間。指針
策略二:code
定義一個left,一個righthtm
1. 遇到1,left++blog
2. 遇到2,和right位置換排序
3. 遇到0,往前和第一個非零數字換,left++索引
class Solution { public: void sortColors(int A[], int n) { int left = 0, right = n -1; while(left <= right) { if (A[left] == 0) { int index = left - 1; while(index >= 0 && A[index] != 0) index--; // 這個算掃描一次嗎? if (index < 0) swap(A[0], A[left]); else swap(A[index+1], A[left]); left++; } else if (A[left] == 1) ++left; else if (A[left] == 2) { swap(A[left], A[right]); right--; } } } };
策略三:get
藉助於快速排序的partition思想,以1爲樞紐元對數組進行劃分,使0在數組的左邊,2在數組的右邊,1在數組的中間。
class Solution { public: void sortColors(int A[], int n) { //zeroEnd是放0那部分的尾部索引,twoEnd是放2那部分的首部索引 //碰到0放到zeroEnd+1處,碰到2放到twoEnd-1處,碰到1指針後移 int zeroEnd = -1, twoBegin = n, i = 0; while(i < twoBegin) { if(A[i] == 0 && i != ++zeroEnd) swap(A[zeroEnd], A[i]); else if(A[i] == 2 && i != --twoBegin) swap(A[twoBegin], A[i]); else i++; } } };
2015/03/31:
class Solution { public: void sortColors(int A[], int n) { if(n <= 1) return; int start = 0, end = n - 1; int i = 0; while(i <= end){ if(A[i] == 0 && i != start){ swap(A, start++, i); }else if(A[i] == 2 && i != end){ swap(A, i, end--); }else ++i; } } private: void swap(int A[], int i, int j){ int temp = A[i]; A[i] = A[j]; A[j] = temp; } };