荷兰国旗问题的算法实现
2013-10-23 17:17 Ross Wang 阅读(1275) 评论(0) 编辑 收藏 举报一个字符串只有‘R’、‘G’、‘B’组成,如何让所有的‘R’出现在前面,所有的‘G’在中间,所有的‘B’在最后。
要求:要求空间复杂度为O(1),只许遍历一遍字符串数组
之所以叫荷兰国旗,是因为我们可以将红白蓝三色小球想象成条状物,有序排列后正好组成荷兰国旗。如下图所示:
算法思路
1. 维护三个游标 headPos、currentPos 、tailPos
2. headPos 指向开始, tailPos 指向尾部,用于分别插入 R 、B
3. currentPos 用于遍历,当发现是R时,与前面的 headPos 指的对象交换,然后 headPos 后移;当发现是B时,与后面的 tailPos 指的对象交换,tailPos 前移,并对 currentPos 所指的新值运行这一步(递归)
4. 当 currentPos 与 tailPos 相遇后停止
完整代码:
#include<iostream> #include<string> /************************ 遍历过程中遇到 B 时的处理逻辑,递归实现 currentPos 当前位置 tailPos 动态尾部位置 headPos 动态头部位置 ************************/ void HandleB(const int ¤tPos,int *tailPos,int *headPos,std::string *str) { if((*str)[--(*tailPos)] == 'B') { if( currentPos == (*tailPos)-1) (*str)[currentPos] = 'B'; else HandleB(currentPos,tailPos,headPos,str); } else { if((*str)[*tailPos] == 'R') (*str)[(*headPos)++] = 'R'; (*str)[*tailPos] = 'B'; } } int main() { std::string str; //方便多次测试 while(true) { str.clear(); //获取测试数据 std::cout << "Please input R G B string with random order...\n" <<"Or input exit to quit." << std::endl ; std::cin >> str; if(str.empty() ) { std::cout << "Input is empty.\n" << std::endl ; continue; } //判断是否退出 else if(!strcmp(str.c_str(),"exit")) break; std::cout <<"Input str is: "<< str <<"\n\n"<< std::endl ; int headPos = 0, tailPos = str.size() ; //开始遍历比较 for(int currentPos= 0; currentPos<tailPos ; currentPos++) { char c = str[currentPos] ; if(c != 'R' && c != 'G' && c != 'B') { std::cout << "Invalid char: "<<c<< std::endl ; break; } //假设所有数据都是G str[currentPos] = 'G' ; if( c == 'R') { str[headPos++] = c ; } else if( c == 'B') { //如果这时动态尾部tailPos所指数据是B,就需要让tailPos再往前 HandleB(currentPos,&tailPos,&headPos,&str); } std::cout <<" "<< str << std::endl ; } std::cout <<"\n\nOrdered str is: "<< str << std::endl ; } }