字符串相关类型题目及其实现
2016-05-22 13:13
288 查看
1. 拓扑结构相同子树
对于两棵彼此独立的二叉树A和B,请编写一个高效算法,检查A中是否存在一棵子树与B树的拓扑结构完全相同。给定两棵二叉树的头结点A和B,请返回一个bool值,代表A中是否存在一棵同构于B的子树。
方法1:
使用递归的方式, 依次判断A 中 每个节点是否与 B 子树相同
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class IdenticalTree { public: bool chkIdentical(TreeNode* A, TreeNode* B) { // write code here if (A == nullptr && B == nullptr) return true; else if (A == nullptr || B == nullptr) return false; else return isSame(A, B) || chkIdentical(A->left, B) || chkIdentical(A->right, B); } private: bool isSame(TreeNode* A, TreeNode* B){ if (A && B && A->val == B->val){ return isSame(A->left, B->left) && isSame(A->right, B->right); } else if (A == nullptr && B == nullptr) return true; else return false; } };
方法二:
将两颗树, 序列化成 两个string, 然后将问题转化为 在一个字符串中查找另一个字符串, 当然可以直接借助string 的find 方法, 这里我们按照自己的思路实现了一个kmp, 虽然思路差不多, 不过代码上, 还是相差蛮大的。
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class IdenticalTree { public: bool chkIdentical(TreeNode* A, TreeNode* B) { // write code here string strA, strB; seriable(A, strA); seriable(B, strB); vector<int> next = getNext(strB); return KMP(strA, strB, next); //return true; } private:; // 序列化 void seriable(TreeNode * root, string & str){ if (root){ str += to_string(root->val) + ","; seriable(root->left, str); seriable(root->right, str); } else{ str += "#,"; } } // kmp 匹配 vector<int> getNext(const string & str){ vector<int> res(str.size(), 0); for (int i = 1; i < (int)res.size(); i++){ if (i == 1){ res[i] = 1; continue; } int index = i; while (index > 0 && res[index - 1] > 0){ if (str[i - 1] != str[res[index - 1] - 1] && i - 1 != res[index - 1] - 1){ index = res[index - 1]; } else break; } res[i] = (index > 0 && res[index - 1] > 0 ? res[index - 1] : 0) + 1; } return res; } bool KMP(const string & strA, const string & strB, const vector<int> & next){ int j = 0; for (int i = 0; i < int(strA.size()); i++){ if (strA[i] == strB[j]){ j++; if (j >= int(strB.size())){ return true; } } else{ if (j > 1){ j = max(next[j] - 1, 0); i--; } } } return false; } };
2. 词语变形
对于两个字符串A和B,如果A和B中出现的字符种类相同且每种字符出现的次数相同,则A和B互为变形词,请设计一个高效算法,检查两给定串是否互为变形词。给定两个字符串A和B及他们的长度,请返回一个bool值,代表他们是否互为变形词。
测试样例:
“abc”,3,”bca”,3
返回:true
解题思路: 借助hash的思想,只要两个string 中所出现的字符的种类和数目都相等即可, ps: 可以借助一个数组来实现自己的hash表
class Transform { public: bool chkTransform(string A, int lena, string B, int lenb) { // write code here if (lena != lenb) return false; vector<int> arr(256, 0); for (auto item : A){ arr[item]++; } for (auto item : B){ arr[item]--; } for (auto item : arr){ if (item != 0) return false; } return true; } };
3. 两串旋转
如果对于一个字符串A,将A的前面任意一部分挪到后边去形成的字符串称为A的旋转词。比如A=”12345”,A的旋转词有”12345”,”23451”,”34512”,”45123”和”51234”。对于两个字符串A和B,请判断A和B是否互为旋转词。给定两个字符串A和B及他们的长度lena,lenb,请返回一个bool值,代表他们是否互为旋转词。
测试样例:
“cdab”,4,”abcd”,4
返回:true
基本思路是, 如果A, B 构成旋转词, 那么B 一定在 AA 串中, 这里我们还是借助KMP处理, i 为当前元素对应的pos, k为i前一个元素位置对应的pos,
ps: 这里的next 数组第一个元素值 为 -1
class Rotation { public: bool chkRotation(string A, int lena, string B, int lenb) { // write code here string A2 = A.substr(0, lena) + A.substr(0, lena); auto res = GetNext(B); int id = KMP(A2, 2 * lena, B, lenb, res); return id >= 0; } private: vector<int> GetNext(const string & str){ if (str.size() == 0) return vector<int>(); int k = -1, i = 0; int len = str.size(); vector<int> vec(len, 0); vec[0] = -1; while (i < len - 1){ if (k == -1 || str[k] == str[i]){ k++, i++; if (str[k] != str[i]) vec[i] = k; else vec[i] = vec[k]; } else{ k = vec[k]; } } return vec; } int KMP(const string & strA, int lena, const string & strB, int lenb, const vector<int> & next){ int i = 0, j = 0; while (i < lena && j < lenb){ if (j == -1 || strA[i] == strB[j]){ i++, j++; } else{ j = next[j]; } } return (j == lenb) ? i - j : -1; } };
4. 句子逆序
对于一个字符串,请设计一个算法,只在字符串的单词间做逆序调整,也就是说,字符串由一些由空格分隔的部分组成,你需要将这些部分逆序。给定一个原字符串A和他的长度,请返回逆序后的字符串。
测试样例:
“dog loves pig”,13
返回:”pig loves dog”
基本思路: 对每个word进行反转, 然后对整体的句子进行反转
class Reverse { public: string reverseSentence(string A, int n) { // write code here int pos = 0; while (pos < n){ int next = A.find(' ', pos); if (next == -1){ reverseWord(A, pos, n - 1); break; } else{ reverseWord(A, pos, next - 1); pos = next + 1; } } reverseWord(A, 0, n - 1); return A; } private: void reverseWord(string & str, int begin, int stop){ while (begin < stop){ swap(str[begin++], str[stop--]); } } };
5. 字符串移位
对于一个字符串,请设计一个算法,将字符串的长度为len的前缀平移到字符串的最后。给定一个字符串A和它的长度,同时给定len,请返回平移后的字符串。
测试样例:
“ABCDE”,5,3
返回:”DEABC”
这里的思路和 4 中的思路一致
class Translation { public: string stringTranslation(string A, int n, int len) { // write code here if (n > len){ reverseWord(A, 0, len - 1); reverseWord(A, len, n - 1); reverseWord(A, 0, n - 1); } return A; } private: void reverseWord(string & str, int begin, int stop){ while (begin < stop){ swap(str[begin++], str[stop--]); } } };
6. 拼接最小字典序
对于一个给定的字符串数组,请找到一种拼接顺序,使所有小字符串拼接成的大字符串是所有可能的拼接中字典序最小的。给定一个字符串数组strs,同时给定它的大小,请返回拼接成的串。
测试样例:
[“abc”,”de”],2
“abcde”
本质上, 可以看成是一种排序, 确定好排序的方法就好了
class Prior { public: string findSmallest(vector<string> strs, int n) { // write code here sort(strs.begin(), strs.end(), cmp); string res; for (auto item : strs) res += item; return res; } private: static bool cmp(const string & str1, const string & str2){ return str1 + str2 < str2 + str1; } };
7. 空格替换
请编写一个方法,将字符串中的空格全部替换为“%20”。假定该字符串有足够的空间存放新增的字符,并且知道字符串的真实长度(小于等于1000),同时保证字符串由大小写的英文字母组成。给定一个string iniString 为原始的串,以及串的长度 int len, 返回替换后的string。
测试样例:
“Mr John Smith”,13
返回:”Mr%20John%20Smith”
”Hello World”,12
返回:”Hello%20%20World”
基本思路: 从后向前依次将数据拷贝到相应位置即可
class Replacement { public: string replaceSpace(string iniString, int length) { // write code here int blanks = 0; for (int i = 0; i < int(iniString.size()); i++){ if (iniString[i] == ' ') blanks++; } string res(length + blanks * 2, ' '); int i = length - 1, id = length + blanks * 2 - 1; while (i >= 0){ if (iniString[i] == ' '){ res[id--] = '0'; res[id--] = '2'; res[id--] = '%'; i--; } else{ res[id--] = iniString[i--]; } } return res; } };
8. 合法括号序列判断
对于一个字符串,请设计一个算法,判断其是否为一个合法的括号串。给定一个字符串A和它的长度n,请返回一个bool值代表它是否为一个合法的括号串。
测试样例:
“(()())”,6
返回:true
测试样例:
“()a()()”,7
返回:false
测试样例:
“()(()()”,7
返回:false
这里选用的思路非常巧妙, 维护一个左右括号数量的差的变量, 如果他这个变量不满足要求, 返回false
class Parenthesis { public: bool chkParenthesis(string A, int n) { // write code here int num = 0; for (int i = 0; i < n; i++){ if (A[i] == '(') num++; else if (A[i] == ')') num--; if (num < 0) return false; } return num == 0; } };
9. 最长无重复字串
对于一个字符串,请设计一个高效算法,找到字符串的最长无重复字符的子串长度。给定一个字符串A及它的长度n,请返回它的最长无重复字符子串长度。保证A中字符全部为小写英文字符,且长度小于等于500。
测试样例:
“aabcb”,5
返回:3
基本思路, 维护一个map 用来记录当前元素上一次出现的位置, 以及len_i 记录以当前元素结尾的符合要求的字串的最大长度, 向后遍历的过程中依次比较计算得到新的节点的len_i , 同时更新最大长度 maxlen 即可
class DistinctSubstring { public: int longestSubstring(string A, int n) { // write code here map<char, int> mymap; int len_i = 0, maxlen = 0; for (int i = 0; i < n; i++){ if (mymap.count(A[i]) == 0){ //len_i = max(len_i, i + 1); len_i += 1; mymap[A[i]] = i; } else{ int pos = mymap[A[i]]; if (i - pos > len_i + 1){ len_i = len_i + 1; } else{ len_i = i - pos; } mymap[A[i]] = i; } maxlen = max(maxlen, len_i); } return maxlen; } };
相关文章推荐
- Android之获取手机上的图片和视频缩略图thumbnails
- android string.xml文件中的整型和string型代替
- Android java 与 javascript互访(相互调用)的方法例子
- android上改变listView的选中颜色
- String.intern
- Prototype源码浅析 String部分(二)
- Ruby中的String对象学习笔记
- PostgreSQL ERROR: invalid escape string 解决办法
- 浅谈C++中的string 类型占几个字节
- 标准C++类string的Copy-On-Write技术
- C++实现string存取二进制数据的方法
- C#中string和StingBuilder内存中的区别实例分析
- 详解C++中实现继承string类的MyString类的步骤
- PHP STRING 陷阱原理说明
- c#中 String和string的区别介绍
- C#实现的图片、string相互转换类分享
- asp.net String.IsNullOrEmpty 方法
- JavaScript中字符串(string)转json的2种方法
- C#中string用法实例详解
- 浅析C#中StringBuilder类的高效及与String的对比