原题:
一个数组,里边存放三种球颜色值:红球为 'R',绿球为 'G ',蓝球为 'B ',
编程对该数组排序,使该数组最后的颜色排列如下:前边元素全部为 'R ',中间元素全部为 'G ',后边为 'B '
----------------------------------------------------------------------------------------------------------------------------------------------------
这道题在csdn论坛上一个03年发的帖子上有人讨论过,我这两天刚看到,集中看了集中解法,自己也给出了几种,这里一并说一下。(我在笔试中遇到过这道题目,同学去笔试时也有遇到,很值得探讨)
我在笔的时候:要求尽可能用swap,不允许分配连续的辅助空间。这里的解答就按照这个要求来:
方案①:我看到题目后立即想到的一种解法,时间复杂度较大,为0(n平方),空间复杂度O(1)。 用的冒泡排序。(这里给出这种不太好的解法,权当复习冒泡排序了)
void SortRGB(char* pData)
{
if(pData == NULL)
{
return;
}
int len = strlen(pData);
if(len<=1)
{
return;
}
char* temp ="RG";
int m = 0;
bool exchange;
int begin = 0;
while(begin<len)
{
exchange = false;
for(int j = len-1;j>=begin;j--)
{
if(pData[j] == temp[m])
{
if(j-1>=0)
swap(pData[j-1],pData[j]);
exchange = true;
}
}
begin++;
if(exchange == false)
{
m = 1;
}
}
}
上边的算法用的就是冒泡排序的思想,这导致时间复杂度很大。而真实的BubbleSort也不需要这么繁琐,只要两个嵌套的for循环就可以。
每一趟遍历要将一个元素冒到最前边。如果某一趟排序过后没有发生交换,则说明排序结束。
方案②:降低时间复杂度,使之为0(n),不过需要两趟遍历。
void SortRGB(char* pData)
{
if(pData == NULL)
{
return;
}
int len = strlen(pData);
if(len<=1)
{
return;
}
char* temp = "RG";
int ptr = 0;
int low = 0;
int high = len-1;
while(low<high && ptr<2)
{
while(pData[low] == temp[ptr])
{
low++;
}
while(pData[high] != temp[ptr])
{
high--;
}
if(low<high)
{
swap(pData[low],pData[high]);
}
else
{
high = len-1;
ptr++;
}
}
}
这个方案只需要对数组做两次遍历即可,时间复杂度已经大大降低。但是还有没有可以优化的空间而言呢?
分析一下上边两种方法发现:其有一个共同点就是:R和G的排序是分开进行的,亦即:先进行完R后,才会去进行B,有没有可能同时进行2个字母的排序呢?
后来跟同学讨论了下这个问题,大家都觉得有可能,杰哥给出了一种算法,只需要一趟就搞定。
方案③:
void sortRGB(char* str)
{
char* l=str;
int n=strlen(str);
//-----------------------------------------------
while(*l!='/0'&&*l=='R')
{
l++;
}
if(*l=='/0')
{
return;
}
//-----------------------------------------------
char* r = str+n-1;
while(*r=='B'&&r>=str)
{
r--;
}
if(r<0)
{
return;
}
//---------------------------------------------
char* p;
for(p=l; p<=r; p++)
{
while(*p!='G')
{
if(*p=='R')
{
swap(*p, *l++);
while(*l=='R')
l++;
p=max(p, l);
if(p>r) break;
}
if(*p=='B')
{
swap(*p, *r--);
while(*r=='B')
r--;
p=min(p, r);
if(p<l) break;
}
}
}
}