算法——从旋转字符串到翻转单词
2016-03-20 23:00
176 查看
一、字符串的旋转
描述:给定一个字符串,要求将字符串前面的若干字符移到字符串的末尾。例如,将字符串的 “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); }
相关文章推荐
- 视频播放插件Video.js简单使用
- 重构第10天:提取方法(Extract Method)
- HTML5桌面通知(Web Notifications)实例解析
- ECMAScript 6 学习笔记
- MySql中的存储过程
- 微分几何
- 冒泡排序和快速排序
- 软件破解技术之API替换
- hdu5646(数学)
- Android 应用界面开发笔记 自定义控件与Handler -待更新
- CURSOR Expressions
- jquery实现点击复制到剪切板
- OneZero第一次随感
- 深拷贝与浅拷贝
- 第二周学习问题总结
- 设计模式——工厂模式
- String类的深拷贝
- 详解C++的JSON静态链接库JsonCpp的使用方法
- Android5.x 新控件之RecyclerView使用总结
- 单线程模型中Message,Handler,MessageQueue,Looper之间的关系