给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
示例:
输入: [2,0,2,1,1,0] 输出: [0,0,1,1,2,2]
进阶:
- 一个直观的解决方案是使用计数排序的两趟扫描算法。
首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。 - 你能想出一个仅使用常数空间的一趟扫描算法吗?
Partition
将列表元素分为三类:等于一的,大于一的,小于一的。可以用三路partition实现。
在介绍三路partition前,先复习一下经典的二路partition实现。如类似算法导论上的版本:
int partition(vector<int>&arr, int low, int high) { int pivot = arr[low];//选第一个元素作为枢纽元 int location = low;//location指向比pivot小的元素段的尾部 for (int i = low + 1; i <= high; i++)//比枢纽元小的元素依次放在前半部分 if (arr[i] <= pivot) swap(arr[i], arr[++location]); swap(arr[low], arr[location]); return location; }
partition返回的下标,下标及下标左边是全部<=pivot的。如果是想要全部<pivot,可以把if中的小于等于号改为小于号。
第二种写法是双指针的,也是从数组左边取pivot:
int mypartition(vector<int>&arr, int low, int high) { int pivot = arr[low];//选第一个元素作为枢纽元 while(low < high) { while(low < high && arr[high] >= pivot)high--; arr[low] = arr[high];//从后面开始找到第一个小于pivot的元素,放到low位置 while(low < high && arr[low] <= pivot)low++; arr[high] = arr[low];//从前面开始找到第一个大于pivot的元素,放到high位置 } arr[low] = pivot;//最后枢纽元放到low的位置 return low; }
对这个题,三路partition如下:
class Solution { public: void sortColors(vector<int> &nums) { int zero = -1; // [0...zero] == 0 int two = nums.size(); // [two...n-1] == 2 for( int i = 0 ; i < two ; ){ if( nums[i] == 1 ) i ++; else if ( nums[i] == 2 ) swap( nums[i] , nums[--two]); else{ // nums[i] == 0 assert( nums[i] == 0 ); swap( nums[++zero] , nums[i++] ); } } } };
原文地址:https://www.cnblogs.com/hlk09/p/9751138.html
时间: 2024-10-06 18:43:08