快排和归并
1.思想:都使用了分治的思路。归并是先局部有序再组合起来,快排是先大体有序(前半部分小于某个数,后半部分大于某个数)在局部排好。
2.时间复杂度:归并是严格的NlogN;快排平均时间复杂度NlogN(因为标杆的数不一定是在最中间),最坏有可能退化到N^2。
3.空间复杂度:归并需要额外一个空间用来合并,快排可以原地排序。
4.稳定性:快排不稳定,归并可以稳定。
归并排序:
class Solution {
public:
void sortIntegers2(vector<int> &A) {
if (A.size()==0 || A.size()==1) return;
vector<int> tmp(A.size(),0);
mergeSort(A,0,A.size()-1,tmp);
}
void mergeSort(vector<int> &A,int start,int end,vector<int> &tmp) {
if (start>=end) return;
mergeSort(A,start,(start+end)/2,tmp);
mergeSort(A,(start+end)/2+1,end,tmp);
//合并
int index=start;
int left=start;
int right=(start+end)/2+1;
while (left<=(start+end)/2 && right<=end) {
if (A[left]<=A[right]) {
tmp[index++]=A[left++];
}else {
tmp[index++]=A[right++];
}
}
while (left<=(start+end)/2) tmp[index++]=A[left++];
while (right<=end) tmp[index++]=A[right++];
for (int i=start;i<=end;i++)
A[i]=tmp[i];
}
};
快排:
class Solution {
public:
void sortIntegers2(vector<int> &A) {
if (A.size()==0 || A.size()==1) return;
vector<int> tmp(A.size(),0);
quickSort(A,0,A.size()-1);
}
void quickSort(vector<int> &A,int start,int end) {
if (start>=end) return;
//也可以随机取,经验上这样取比较好,如果取首尾很有可能退化成最坏情况
int pivot=A[(start+end)/2];
int left=start;
int right=end;
//注意有=,否则在[1,2]这种情况会一直分成[1],[1,2],会出错
while(left<=right){
//注意第二个条件没有等号,允许等于pivot的数分布在两个部分,尽量使左右两部分数字个数不要相差太多,否则会退化
while(left<=right && A[left]<pivot) {
left++;
}
while(left<=right && A[right]>pivot) {
right--;
}
if (left<=right) {
swap(A[left],A[right]);
left++;
right--;
}
}
//这时right已经在left左边了
quickSort(A,start,right);
quickSort(A,left,end);
}
};
143. 排颜色 II
如果没有原地排序的要求,可以使用计数排序。原地的话类似快排,只不过pivot不是随机找的而是根据颜色区间定的。由于pivot也是由colorTo和colorFrom定的,所以要注意往两边排序的条件,左边是小于等于,右边是大于。
class Solution {
public:
void sortColors2(vector<int> &colors, int k) {
if (colors.size()==0 ||colors.size()==1) return;
sort(colors,0,colors.size()-1,1,k);
}
void sort(vector<int> &colors,int start,int end,
int colorsFrom, int colorsTo) {
if (start>=end || colorsTo==colorsFrom) return;
int mid=(colorsTo+colorsFrom)/2;
int i=start;
int j=end;
while (i<=j) {
//由于mid是取上整,为了避免i左边没有数,应该把等于mid的情况归类到左边;
while (i<=j && colors[i]<=mid) i++;
while (i<=j && colors[j]>mid) j--;
if (i<=j) {
swap(colors[i],colors[j]);
i++;
j--;
}
}
sort(colors,start,j,colorsFrom,mid);
sort(colors,i,end,mid+1,colorsTo);
}
};