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

来源:互联网 发布:linux 用户安全设置 编辑:程序博客网 时间:2024/06/08 14:46

一、字符串的旋转

描述:给定一个字符串,要求将字符串前面的若干字符移到字符串的末尾。例如,将字符串的 “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);}
0 0
原创粉丝点击