算法——从旋转字符串到翻转单词

一、字符串的旋转

描述:给定一个字符串,要求将字符串前面的若干字符移到字符串的末尾。例如,将字符串的 “abcdef” 的前面 3 个字符 ‘a’, ‘b’ ‘c’ 移到字符串的末尾,那么原字符串将变成 “defabc”。

解法一:蛮力移位(循环左移)

较为直观的一种解法即是,将需要移动的字符使用循环左移(ROL,Ring Shift Left)的方式一个一个地移到字符串的尾部。

// 循环左移 1 位,循环左移k位的辅助函数
void ROL1(char* s, int n)
{
    char t = s[0];
    for (int i = 1; i < n; ++i)
        s[i-1] = s[i];
    s[n-1] = s[0];
}
// 循环左移 k 位
void ROLK(char* s, int n, int k)
{
    while (k--)                       // while (--k) 会比 while (k--) 少做一次循环
        ROL1(s, n);
}

时间复杂度分析:对于长度为 n 的字符串,如果左移 m 位的话,时间复杂度为 O(mn).

解法二:三步反转

这是一个稍具 Tricky 的解法,且解法具有普世性,句子中单词的翻转,即可使用该解法解决:

  • (1)将源字符串分为 X 和 Y 两部分,其中 X 为 “abc”,Y 为 “def”
  • (2)翻转 X,翻转 Y,X ⇒ “cba”,Y ⇒ “fed”
  • (3)整体翻转,”cbafed” ⇒ “defabc”
// 辅助函数
void ReverseString(char* s, int from, int to)
{
    while (from  < to)
    {
        char t = s[from];
        s[from++] = s[to];
        s[to--] = t;
    }
}

// 三步反转
void LeftRotateString(char* s, int n, int m)
{
    m %= n;
    ReverseString(s, 0, m-1);
    ReverseString(s, m, n-1);
    ReverseString(s, 0, n-1);
}

时间复杂度为:O(n)

二、单词的翻转

输入一个英文句子,翻转句子中单词的顺序,要求单词内字符的顺序不变,句子中单词以空格符隔开。为简单起见,标点符号和普通字母做同样处理。

“I am a student.” ⇒ “student. a am I”

沿用“三步反转”法的思路,先将每个单词自翻转,再整体翻转,求解的难点在于,每个单词的确定,我们使用数组索引的方式确定每个单词的起始和截止。

void ReverseWords(char* s, int n)
{
    int arr[255] = { 0 };
    int idx = 0;
    for (int i = 0; i < n; ++i)
    {
        if (s[i] == ' ')
            arr[idx++] = i;
    }
    idx -= 1;
    ReverseString(s, 0, arr[0]-1);
    for (int i = 0; i < idx; ++i)
    {
        ReverseString(s, arr[i]+1, arr[i + 1]-1);
    }
    ReverseString(s, arr[idx] + 1, n-1);
    ReverseString(s, 0, n - 1);
}

你可能感兴趣的:(算法)