题目
给定一个包含小写英文字母的字符串 s 以及一个矩阵
shift
,其中shift[i] = [direction, amount] direction
可以为 0 (表示左移)或 1 (表示右移)。amount
表示 s 左右移的位数。左移 1 位表示移除 s 的第一个字符,并将该字符插入到 s 的结尾。类似地,右移 1 位表示移除 s 的最后一个字符,并将该字符插入到 s 的开头。对这个字符串进行所有操作后,返回最终结果。
示例 1:
输入:s = “abc”, shift = [[0,1],[1,2]]
输出:“cab”
解释:
[0,1] 表示左移 1 位。 “abc” -> “bca”
[1,2] 表示右移 2 位。 “bca” -> “cab”
示例 2:
输入:s = “abcdefg”, shift = [[1,1],[1,1],[0,2],[1,3]]
输出:“efgabcd”
解释:
[1,1] 表示右移 1 位。 “abcdefg” -> “gabcdef”
[1,1] 表示右移 1 位。 “gabcdef” -> “fgabcde”
[0,2] 表示左移 2 位。 “fgabcde” -> “abcdefg”
[1,3] 表示右移 3 位。 “abcdefg” -> “efgabcd”
提示:
-
1 <= s.length <= 100 s 只包含小写英文字母
-
1 <= shift.length <= 100
-
shift[i].length == 2
-
0 <= shift[i][0] <= 1
-
0 <= shift[i][1] <= 100
思路
方法一(暴力)
遍历shift
数组,判断当前是向左移还是向右移,在根据移动次数,每次移动字符串中的一位。
代码实现
#include<string.h>
char* stringShift(char* s, int** shift, int shiftSize, int* shiftColSize) {
int i = 0;
int len_s = strlen(s);
for(i = 0; i < shiftSize; i++){
//direction表示移动方向,amount表示移动次数
int direction = shift[i][0];
int amount = shift[i][1];
//判断是左移还是右移动
if(0 == direction){ //左移动
int j = 0;
for(j = 0; j < amount; j++){ //移动的次数
char tmp = s[0]; //保留第一位
int k = 0;
for(k = 0; k < len_s - 1; k++){ //每次左移一位
s[k] = s[k + 1];
}
s[len_s - 1] = tmp; //将第一位添加到字符串末尾
}
}else{ //右移动
int j = 0;
for(j = 0; j < amount; j++){ //移动次数
char tmp = s[len_s - 1]; //保留最后一位
int k = len_s - 1;
for(k = len_s - 1; k > 0 ; k++){ //每次右移一位
s[k] = s[k - 1];
}
s[0] = tmp; //添加到字符串开头
}
}
}
return s;
}
方法二(方法一改进)
方法一中,我们将移动分为了向左移动和向右移动,而这里我们可以将向右移动看成向左移动,只不过是移动次数不在是shift数组中的amount
,我们观察可以知道,如果字符串向右移动amount
次,可以等效为向左移动len - amount
次。不过这里的前提是amount
必须小于len
所以我们可以进行取余运算这样得到的次数肯定是在0~len
当中。
代码实现
#include<string.h>
char* stringShift(char* s, int** shift, int shiftSize, int* shiftColSize) {
int i = 0;
int len_s = strlen(s);
for(i = 0; i < shiftSize; i++){
//direction表示移动方向,amount表示移动次数
int direction = shift[i][0];
int amount = shift[i][1];
amount %= len;
if(0 == direction){
amount = amount;
}else{
amount = len - amount;
}
int j = 0;
for(j = 0; j < amount; j++){ //移动的次数
char tmp = s[0]; //保留第一位
int k = 0;
for(k = 0; k < len_s - 1; k++){ //每次左移一位
s[k] = s[k + 1];
}
s[len_s - 1] = tmp; //将第一位添加到字符串末尾
}
}
return s;
}
方法三
方法二虽然在方法一的基础上在移动方向上进行一定程度改进,使得代码进行简化,然而其时间复杂度还没有改变。这里我们在观察,如果一个字符串abcdef
先向左移动 2 次,得到cdefab
,在向右移动 1 次,得到bcdefa
,在向左移动 2 次得到defabc
,这个结果和原字符串abcdef
直接向左移动 3 次的结果是一样的,所以,我们在移动之前可以先统计出需要移动的次数,由于在方法二中我们将移动简化为只有向左移动一种情况,那么不需要考虑正负问题。
代码实现
#include<string.h>
char* stringShift(char* s, int** shift, int shiftSize, int* shiftColSize) {
int i = 0;
int len_s = strlen(s);
int totalAmount = 0; //表示总移动次数
for(i = 0; i < shiftSize; i++){
//direction表示移动方向,amount表示移动次数
int direction = shift[i][0];
int amount = shift[i][1];
amount %= len_s;
if(1 == direction){
amount = len_s - amount;
}
totalAmount += amount;
}
totalAmount %= len_s; //取余保证移动次数在 0~len内
int j = 0;
for(j = 0; j < totalAmount; j++){ //移动的次数
char tmp = s[0]; //保留第一位
int k = 0;
for(k = 0; k < len_s - 1; k++){ //每次左移一位
s[k] = s[k + 1];
}
s[len_s - 1] = tmp; //将第一位添加到字符串末尾
}
return s;
}
方法四
在上述方法中,虽然简化了移动方向和移动次数的问题,但是我们在移动字符串时,依旧是每次移动一位,使得效率比较低。如果我们能够事先知道每一个字符需要移动的位置,在借助辅助数组,遍历字符串时将移动后当前位置对应的字符填入即可。
代码实现
#include<string.h>
char* stringShift(char* s, int** shift, int shiftSize, int* shiftColSize) {
int i = 0;
int len_s = strlen(s);
int totalAmount = 0; //表示总移动次数
for(i = 0; i < shiftSize; i++){
//direction表示移动方向,amount表示移动次数
int direction = shift[i][0];
int amount = shift[i][1];
amount %= len_s;
if(1 == direction){
amount = len_s - amount;
}
totalAmount += amount;
}
totalAmount %= len_s; //取余保证移动次数在 0~len内
int j = 0;
int tmp[len_s]; //辅助数组用于保存S字符串内容
for(i = 0; i < len_s; i++){
tmp[i] = s[i];
}
for(j = 0; j < len_s; j++){
s[i] = tmp[(i + amount) % len_s];
}
return s;
}
方法五
观察字符串, 假设有一字符串abcdefg totalAmount = 3
,那么移动后字符串defgabc
,对比移动前和移动后:
移动前abc | defg
移动后defg | abc
就是将defg
和abc
互换位置得到,再来看一个特殊情况:
移动前ab
移动后ba
ab
移动一步得到ba
,而反转ab
也能得到ba
那么是否可以通过反转移动前的字符串来得到移动后的字符串呢
移动前 abc | defg
反转abc
和 defg
得到:cba | gfed
在反转整个字符串得到defg | abc
就得到了移动后的字符串,所以我们可以通过反转字符串来达到移动的效果
代码实现
#include<string.h>
//反转字符串s中start~end部分[start,end)
void reverse(char* s,int start,int end){
end--;
while(start < end){
char tmp = s[start];
s[start] = s[end];
s[end] = tmp;
start++;
end--;
}
}
char* stringShift(char* s, int** shift, int shiftSize, int* shiftColSize) {
int i = 0;
int len_s = strlen(s);
int totalAmount = 0; //表示总移动次数
for(i = 0; i < shiftSize; i++){
//direction表示移动方向,amount表示移动次数
int direction = shift[i][0];
int amount = shift[i][1];
amount %= len_s;
if(1 == direction){
amount = len_s - amount;
}
totalAmount += amount;
}
totalAmount %= len_s; //取余保证移动次数在 0~len内
reverse(s,0,totalAmount);
reverse(s,totalAmount,len_s);
reverse(s,0,len_s);
return s;
}
若有错误或不足还请指出