- 問題説明
左シフトとは、文字列の先頭にある指定された数の文字を末尾に移動することです。
例えば、"ABCDEF"を2文字左シフトすると"BCDEFAB"となり、3文字左シフトすると"DEFABC"になります。
- 実装コード
void left_shift(char* str, int k)
{
int j = 0;
assert(str);
for (j = 0; j < k; j++)
{
char temp = *str;
int len = strlen(str);
int i = 0;
for (i = 0; i < len - 1; i++)
{
*(str + i) = *(str + i + 1);
}
*(str + len - 1) = temp;
}
}
int main()
{
char arr[] = "abcdefgh";
int k = 0;
scanf("%d", &k);
left_shift(arr, k);
printf("%s\n", arr);
return 0;
}
(1)このロジックは、条件に合致する各文字を前に移動します。
(2)最初の文字をコピーし、すべての文字が前へ移動した後に、そのコピーを最後に配置します。このプロセスを繰り返します。
- コード最適化
// 上記のアルゴリズムを改善しました。元の方法では一部の要素が複数回移動されるため、効率が低下していました。
void reverse(char* left, char* right)
{
while (left < right)
{
char temp = *left;
*left = *right;
*right = temp;
left++;
right--;
}
}
void left_shift(char* str, int k)
{
int len = strlen(str);
// 左半分を逆順にする
reverse(str, str + k - 1);
// 右半分を逆順にする
reverse(str + k, str + len - 1);
// 全体を逆順にする
reverse(str, str + len - 1);
}
int main()
{
char arr[] = "abcdefgh";
int k = 0;
scanf("%d", &k);
left_shift(arr, k);
printf("%s\n", arr);
return 0;
}
(1)元の方法では後半の文字列が複数回移動されるため、無駄があります。
(2)この方法は巧妙で、思いつかない人も多いかもしれません。これは、左シフトしたい文字列を逆順にし、残りの文字列も逆順にし、最後に全体を逆順にするというものです。結果として、必要な文字列を得ることができます。
- 左シフトの確認
ある文字列が別の文字列の左シフトによって生成されたかどうかを判断する方法
int is_left_shift(char* str1, char* str2)
{
int j = 0;
assert(str1 && str2);
int len = strlen(str1);
for (j = 0; j < len; j++)
{
char temp = *str1;
int i = 0;
for (i = 0; i < len - 1; i++)
{
*(str1 + i) = *(str1 + i + 1);
}
*(str1 + len - 1) = temp;
if (strcmp(str1, str2) == 0)
return 1;
}
return 0;
}
int main()
{
char arr1[] = "abcdefgh";
char arr2[] = "efghabcd";
int ret = is_left_shift(arr1, arr2);
if (ret == 1)
{
printf("yes\n");
}
else
{
printf("not\n");
}
return 0;
}
(1)この方法では、標準ライブラリ関数を使用して、既知の文字列を左シフトし、毎回もう一つの文字列と比較します。比較にはstrcmp関数を使用します。
int is_left_shift(char* str1, char* str2)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
if (len1 != len2)
{
return 0;
}
strncat(str1, str1, len1);
if ((strstr(str1, str2) == NULL))
return 0;
else
return 1;
}
int main()
{
char arr1[30] = "abcdefgh";
// 二度繰り返すことで、すべての可能性をカバーできます
char arr2[] = "efghabcd";
int ret = is_left_shift(arr1, arr2);
if (ret == 1)
{
printf("yes\n");
}
else
{
printf("not\n");
}
return 0;
}
(1)これはより効率的なアプローチです。文字列を二度繰り返すことで、すべての可能なケースを取得できます。
(2)str1を二つの部分に結合し、strncat関数を使用して配列に格納します。その後、strstr関数を使ってstr2が含まれているかを確認します。含まれていなければNULLが返され、含まれていれば1が返されます。これにより、ループを行う必要がありません。