在一个由 'L'
, 'R'
和 'X'
三个字符组成的字符串(例如"RXXLRXRXL"
)中进行移动操作。一次移动操作指用一个"LX"
替换一个"XL"
,或者用一个"XR"
替换一个"RX"
。现给定起始字符串start
和结束字符串end
,请编写代码,当且仅当存在一系列移动操作使得start
可以转换成end
时, 返回True
。
示例 :
输入: start = "RXXLRXRXL", end = "XRLXXRRLX" 输出: True 解释: 我们可以通过以下几步将start转换成end: RXXLRXRXL -> XRXLRXRXL -> XRLXRXRXL -> XRLXXRRXL -> XRLXXRRLX
思路:双指针
用一个"LX"替换一个"XL",或者用一个"XR"替换一个"RX" 这句话等价于:
把字符串中的X想象成一种溶质,L只能向左移动穿过溶质X,R只能向右移动穿过溶质X。
所以用两个指针分别指向start与end,遇到X就穿过去,如果start[i]==end[j],若都是R,那就得保证i<=j,因为R只能穿过溶质X向右移动;都是L时,得保证i>=j,因为L只能穿过溶质X向左移动。
如果有一方已经遍历到末尾,那么剩下的那一方,未遍历的部分一定都得是X,不然就无法匹配了。
class Solution {
public:
bool canTransform(string start, string end) {
int n=start.size();
if(n!=end.size())//长度不同,肯定无法转换
return false;
int i=0,j=0;//两个指针分别指向start和end
while(i<n&&j<n)
{
while(start[i]=='X')//跳过X
i++;
while(end[j]=='X')
j++;
if(start[i]==end[j])
{
if(start[i]=='R')//都是R时,要求i<=j,因为R只能向右移动
{
if(i<=j)
{
i++;
j++;
}
else
return false;
}
if(start[i]=='L')//都是L时,要求i>=j,因为L只能向左移动
{
if(i>=j)
{
i++;
j++;
}
else
return false;
}
}
else//两个不相等,肯定无法转换
{
return false;
}
}
while(i<n)//如果j已经走到末尾,i还没有
{
if(start[i]!='X')//i后面得全都是X才行
return false;
i++;
}
while(j<n)//如果i已经走到末尾,j还没有
{
if(end[j]!='X')//j后面得全都是X才行
return false;
j++;
}
return true;
}
};
字符串轮转。给定两个字符串s1
和s2
,请编写代码检查s2
是否为s1
旋转而成(比如,waterbottle
是erbottlewat
旋转后的字符串)。
示例1:
输入:s1 = "waterbottle", s2 = "erbottlewat" 输出:True
示例2:
输入:s1 = "aa", s2 = "aba" 输出:False
思路:
首先,如果s1和s2的长度不一样,那么无论怎么轮转,s1都不能轮转成s2 。字符串 s1+s1 包含了所有 s1可以通过轮转操作得到的字符串,只需要检查 s2是否为 s1+s1 的子字符串即可。检查子串使用KMP算法。
class Solution {
public:
bool isFlipedString(string s1, string s2) {
if(s1.size()!=s2.size())//如果两字符串长度不同,那么肯定不能轮转得到
return false;
s1+=s1;//让s1扩大一倍,接上自己
//string中的find函数,从0开始找,返回匹配字符串第一个字符的索引(从0开始),找不到返回string::npos
//find函数实现的原理是KMP算法,时间复杂度为O(n)
if(s1.find(s2,0)==string::npos)//如果在s1母串中可以找到s2子串,那么可以轮转得到,反之则不能
{
return false;
}
else
{
return true;
}
}
};
有两个长度相同的字符串 s1
和 s2
,且它们其中 只含有 字符 "x"
和 "y"
,你需要通过「交换字符」的方式使这两个字符串相同。
每次「交换字符」的时候,你都可以在两个字符串中各选一个字符进行交换。
交换只能发生在两个不同的字符串之间,绝对不能发生在同一个字符串内部。也就是说,我们可以交换 s1[i]
和 s2[j]
,但不能交换 s1[i]
和 s1[j]
。
最后,请你返回使 s1
和 s2
相同的最小交换次数,如果没有方法能够使得这两个字符串相同,则返回 -1
。
示例 1:
输入:s1 = "xx", s2 = "yy" 输出:1 解释: 交换 s1[0] 和 s2[1],得到 s1 = "yx",s2 = "yx"。
示例 2:
输入:s1 = "xy", s2 = "yx" 输出:2 解释: 交换 s1[0] 和 s2[0],得到 s1 = "yy",s2 = "xx" 。 交换 s1[0] 和 s2[1],得到 s1 = "xy",s2 = "xy" 。 注意,你不能交换 s1[0] 和 s1[1] 使得 s1 变成 "yx",因为我们只能交换属于两个不同字符串的字符。
示例 3:
输入:s1 = "xx", s2 = "xy" 输出:-1
示例 4:
输入:s1 = "xxyyxyxyxx", s2 = "xyyxyxxxyx" 输出:4
提示:
1 <= s1.length, s2.length <= 1000
s1, s2
只包含'x'
或'y'
。
思路:贪心
首先,如果完成交换之后s1和s2相同,则表明s1、s2中的x总数和y总数都应是偶数,因为s1里有一个那么s2的对应位置也应该有一个相同的,肯定是2的倍数。
所以,先遍历字符串s1、s2,找出其中位置相同但字符不同的元素个数diff。
如果diff是奇数,那么无法通过交换使得s1=s2。因为s1、s2中位置相同且字符相同的元素个数一定是2的倍数,但是字符不同的元素个数却是奇数,奇数+偶数是奇数,所以不满足s1、s2中x总数和y总数是偶数的先决条件。
如果diff是偶数,且字符不同的元素中x的个数也是偶数,那么通过diff / 2次的交换,即可使s1=s2。(两两一队)
如果diff是偶数,且字符不同的元素中x的个数是奇数,那么通过diff / 2+1 次的交换,即可使s1=s2。因为通过一次交换,让s1中多一个x,s2中少一个x(s1中少一个y,s2中多一个y)就可以让它变成“字符不同的元素中x的个数是偶数”这种情况。
class Solution {
public:
int minimumSwap(string s1, string s2) {
int xdiff=0;
int ydiff=0;
for(int i=0;i<s1.size();i++) {
if(s1[i]!=s2[i]) {
if(s1[i]=='x')
xdiff++;
else
ydiff++;
}
}
int diff=xdiff+ydiff;
if(diff%2!=0)
return -1;
else
if(xdiff%2==0)
return diff/2;
else
return diff/2+1;
}
};