您的位置:首页 > 其它

字符串相关类型题目及其实现

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;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  string