晚上在优快云上看到编程挑战比赛,于是就好奇的打开页面,打算参加,第一题是关于字符串的问题,原题为:
给定两个字符串,仅由小写字母组成,它们包含了相同字符。 求把第一个字符串变成第二个字符串的最小操作次数,且每次操作只能对第一个字符串中的某个字符移动到此字符串中的开头。 例如给定两个字符串“abcd" "bcad" ,输出:2,因为需要操作2次才能把"abcd"变成“bcad" ,方法是:abcd->cabd->bcad。
看了题目后第一想法就是用C++来写程序,字符串用string表示,下面就是算法了,给定了两个字符串,以第二个为标准,移动第一个来匹配第二个,就相当于给定一个排列,使第一个经过移序后与标准排序更接近,也就是说如果第二个的逆序越来越少,则就越来越接近标准排序。怎样移动才能使逆序减少的最快呢?
其实只要选定一个方向,此处以逆序为准,从后面移动字符,直到最后一个字符与第二个排序的最后一个字符相等,本例中由于最后一个已经与第一个相同,所以不需要移动,这样问题就转化为count=1(一个字符相同,即d) + 去掉相同字符后剩下的字符 abc与bca若满足题目要求需要移动的次数。
分析到这应该感觉到同一个问题,经过一次处理问题就转化为针对更短字符串的问题了,于是就可以使用递归来解决问题。
写了一下实现代码:
#include <string>
#include <iostream>
#include <stdlib.h>
#include <cassert>
using namespace std;
static int count = 0;
int strCompare(string a,const string b);
int main(){
string a1;
string a2;
cout<<"please enter two string:\n";
cin>>a1;
cin>>a2;
cout<<"the least count is "<<strCompare(a1,a2)<<"\n";
return 0;
}
int strCompare(string a,string b){
assert(a!=string(" ") && b != string(" "));
int length = a.size()-1;
if(a == b)
return count;
else{
while(a[length] == b[length])
--length;
count++;
a = a[length] + a.substr(0,length);
while(a[length] != b[length]){
count++;
a = a[length] + a.substr(0,length);
}
return strCompare(a,b.substr(0,length+1));
}
}
进入处理函数,首先判断两个字符串是否相等,如果相等就已经得到正确结果了,否则就从后面开始,首先找到第一个不相等的字符,则需要移动第一个字符串此位置的字符到下标0处,则count需要加1,这时a就变成了a[length]+a.substr(0,length);继续检测,直到相等的字符为止,则原来的大问题就转化为了一个相同的小问题,递归调用既可了。