您的位置:首页 > 编程语言 > C语言/C++

前后重组字符串

2014-09-30 16:32 239 查看
        距离上次写博客已经快一个月了,最近这个月都一直在忙着找工作,现在暂时有了一个offer,刚好昨天去网易笔试了一下,就将里面的题目拿出来做做。

        题目是这样子的:输入一个字符串src,从这个字符串去除头或者尾一个字符,并将这个字符加到另外一个字符串result的尾端,删除了src的所有字符后,要求得到最后的字符串result最小(即要求字符串是生成的字符串是按字符字典最小的字符串),例如输入 src="acdebcb",输出为result="abcbcde"。

        其实题目的意思就是前后不断地取src字符串的字符元素,小的那个先取。题目不是很难,关键步骤是看怎么去处理当前后字符相等时的情况。(刚开始以为自己的思路是正确的,结果在写这篇博客分析的时候,却发现逻辑有点不对,于是又重新想了下,看来写博客也有这方面的好处啊)

        我的思路是这样子的,先设置两个下标变量front和把back分别指向字符串的头和尾,如下图所示:



        看src[front]和src[back]哪个小,小的那个就将其加到result中,并且下标变量更新。

        如果相等,就再设置两个临时变量left和right,分别指向相等的前后两个元素,并调用函数去判断是从字符串的左边还是右边去取数。一开始以为要用递归去判断多重相等的情况,所以就写成函数的形式,后面调试的时候发现是不用递归的,结果后面还是保留了函数的形式,不过这样子看也不错,能把逻辑分开来,好懂一些。

        函数 findIndex 是个逻辑判断函数,首先是处理下标left和right,front和back 的越界情况,然后是多个判断情况。

        1.判断下两个元素,即left和right对应的元素是不是比前面的元素都大,是的话,就返回左边或者右边都可以,这里是返回左边,记得要将left值要减一。

        2.判断如果src[left]不等于src[right]且有一个小于它对应的前一位的值,那么就返回小的值的那一端。

        3.判断如果src[left]等于src[right]且它们小于它的前一位值,那么就循环更新left和right的值。当循环结束时,要考虑是哪个条件导致了循环结束,于是又分为了下面几种情况:

        (1)如果是下标条件越界的,就就随便返回一边,这里是返回左边,记得将left减一,因为之前是越界了。

        (2)这里说明没有越界,然后判断左右是不是相等,如果有小的一端,那么就返回小的那个方向,如果没有小的一端,说明这两个元素相等而且大于前面的元素,那么情况就和前面的情况1是一样的,直接返回一边即可(下标要处理)。

        到这里好像就讨论完了,其实还要处理最后一个当left等于right的时候,那么也要将最后一个元素加到字符串的后面去,那么现在就是真正的结束了。

        下面是代码,代码里面有注释,对应了上面的的分析。可以参照着代码和分析一起看,这样可能容易懂一些。测试了多个用例,感觉是对的,但不保证完全没有错误。另外,这是网易笔试题第一道编程题,感觉是不是应该有更简单的分析方法呢,如果大家有的话欢迎来交流。

//返回值 0代表左边,1代表右边
int findIndex(const std::string& src,int& front,int& back,int& left,int& right)
{
if (front > back || left > right)
{
return 0;
}

//如果下两个元素都比前面的元素大,那么前面的两个元素加到目标字符串的尾部
if (left < right && src[left] > src[front] && src[right] > src[back])
{
left--;
return 0;
}

//如果left和right不相等,而且有一个小于front的元素,那么就将小的那一端的两个元素加到目标字符串尾部
if (left < right && (src[left] < src[front] || src[right] < src[back]) && src[left] != src[right])
{
if (src[left] < src[right])
{
return 0;
}
else if (src[left] > src[right])
{
return 1;
}
}

//如果left和right一直相等而且都是小于前一个数的话,就一直循环,直到下标结束条件或者left和right对应的元素值大于前一个值
while(left < right && src[left] == src[right] && src[left] < src[left-1])
{
left++;
right--;
}

//判断是不是下标条件结束的
if (left >= right)
{
left--;
return 0;
}
else
{
//判断左右是不是还相等
if (src[left] < src[right])
{
return 0;
}
else if(src[left] > src[right])
{
return 1;
}
else
{
//左右还相等的话,到这里,就说明 src[left] >= src[left-1] && src[left] == src[right],
//那么就递归求值
/*left++;
right--;
return findIndex(src,front,back,left,right);*/

//不用递归,直接返回之前的下标即可
left--;
return 0;
}
}
}

std::string ResortString(const std::string src)
{
string result;

int len = src.length();

if (len < 1)
{
return result;
}
else if (1 == len)
{
result = src;
return result;
}

int front = 0,back = len-1;

//两个下标分别标记字符串的头部和尾部
while (front < back)
{
//小的那个字符加到结果字符串中
if (src[front] < src[back])
{
result += src[front++];
}
else if (src[front] > src[back])
{
result += src[back--];
}
else
{
//如果两个元素相等,则另外设两个标志下标
int left = front +1;
int right = back -1;

//调用函数去判断是从左边还是右边取数
int direct = findIndex(src,front,back,left,right);

if (!direct)
{
//左边取数
while(front <= left)
{
result += src[front++];
}
}
else
{
//右边取数
while(back >= right)
{
result += src[back--];
}
}

}
}

//考虑下标相等的情况
if (front == back)
{
result += src[front];
}

return result;
}

//

int main()
{
string str = "acdebcb";	//acbdegfadbcb	aedcezecdea	baezeab	acbdadbcb

cout<<ResortString(str)<<endl;

cout<<"end"<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息