判断两个字符串是否为变形词
给定两个字符串str1和str2,如果str1和str2中出现的字符种类出现的一样且每种字符出现的次数也一样,那么str1和str2互为变形词。请判断str1和str2是否为变形词。
1 输入包括3行,第一行包含两个整数n,m(1 \leq n,m\leq 10^5)(1≤n,m≤105)分别代表str1和str2的长度,第二行和第三行为两个字符串,分别代表str1和str2。
解析:利用hash表对字符串1元素累加,然后对串2中出现在串1的元素累减;判断value是否都是0便可;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23int main()
{
int n, m; cin >> n >> m;
string str1, str2;
cin >> str1 >> str2;
if (str1.size()!= n || str2.size() != m || n != m) {cout << "false"; return 0;}
unordered_map<char, int> table;
for (auto c : str1)
table[c]++;
for(auto c : str2)
{
table[c]--;
}
for (auto it = table.begin(); it != table.end(); it++)
{
if (it->second != 0)
{cout << "false"; return 0;}
}
cout << "true" << endl;
}判断两个字符串是否互为旋转词
如果一个字符串为str,把字符串的前面任意部分挪到后面形成的字符串交str的旋转词。比如str=“12345”,str的旋转串有“12345”、“45123”等等。给定两个字符串,判断是否为旋转词。
- 解析:这里用KMP算法,判断串1与串2是否互为旋转词,可以把串2拼接上串2等到拼接串2,若串1是拼接串2的子串,那么肯定互为旋转词,判断是不是子串,可以用KMP来做。时间空间复杂度都是$O(N)$,满足情况。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using namespace std;
int KMP(const string& str1, const string& pattern)
{
int n = str1.size(), m = pattern.size();
vector<int> next(m, 0);
int k = 0;
for (int i = 1; i < m; i++)
{
while(k > 0 && pattern[k] != pattern[i]) k = next[k - 1];
if (pattern[i] == pattern[k])
next[i] = ++k;
}
k = 0;
for (int i = 0; i < n; i++)
{
while(k > 0 && str1[i] != pattern[k]) k = next[k - 1];
if (str1[i] == pattern[k]) k++;
if (k == m)
{
return i - k + 1;
}
}
return -1;
}
int brute(const string& str1, const string& str2)
{
for (int i = 0; i < str1.size() - str2.size(); i++)
{
int tmp = i;
for (int j = 0; j < str2.size(); j++)
{
if (str1[tmp++] != str2[j])
break;
}
if (tmp == str2.size())
return i;
}
return -1;
}
int main(){
int n, m; cin >> n >> m;
string str1, str2; cin >> str1 >> str2;
if (n != m || str1.size() != n || str2.size() != m)
{cout <<"NO"; return 0;}
string combine = str2 + str2;
cout << (KMP(combine, str1) >= 0 ? "YES" : "NO") << endl;
}
将整数字符串转成整数值
给定一个字符串str,如果str符合日常书写的整数形式,并且属于32位整数范围,返回str代表的整数值,否则返回0。
- 解析:判断数字的符号;判断数字的范围,超出数字范围直接返回false;若为0,必须是在i的最后位置上;判断范围是否在int内。
1 |
|
字符串的统计字符串
给定一个字符串str,返回str的统计字符串。例如“aaabbbbcccd”的统计字符串为“a_3_b_4_c_3_d_1”。
1
2
3 offerofferzainaliiiiii
输出:
o_1_f_2_e_1_r_1_o_1_f_2_e_1_r_1_z_1_a_1_i_1_n_1_a_1_l_1_i_6
- 解析:c++ 直接
ans += str[i - 1] + "_" + to_string(num)
会报错;
1 | string decoder(const string &str) |
判断数组中所有的数字是否只出现一次
给定一个个数字arr,判断数组arr中是否所有的数字都只出现过一次。
1
2 1.时间复杂度O(n)。
2.额外空间复杂度O(1)。
解析:方法1:时间空间复杂度为O(n)的方法,利用hashtable查找;
方法2:非递归的堆排序:它的父节点子节点坐标为:
1
2
3iParent(i) = floor((i-1) / 2) where floor functions map a real number to the smallest leading integer.
iLeftChild(i) = 2*i + 1
iRightChild(i) = 2*i + 2最大堆排序的过程:
1、建立堆:循环从最后一个父节点到第一个父节点开始建立堆;把子节点与父节点对比,子节点大就与父节点交换;然后父节点的索引变为子节点的索引,子节点重新根据父节点计算索引,原因是交换了父节点,可能导致下游的子树不满足最大堆性质;
2、循环交换第一个父节点与最尾部节点,然后对【0,尾部index-1】的部分重新维持堆性质。
1 | /*方法1 |
在有序但是含有空的数组中查找字符串
给定一个字符串数组strs[],在strs中有些位置为null,但在不为null的位置上,其字符串是按照字典序由小到大出现的。在给定一个字符串str,请返回str在strs中出现的最左位置,如果strs中不存在str请输出“-1”。
1 输出包含多行,第一行包含一个整数n代表strs的长度,第二行一个字符串,代表str,接下来n行,每行包含一个字符串构成,字符串只包含小写字符,如果这一行为“0”,代表该行字符串为空,这n行字符串代表strs。(数据保证当字符串不为空时,所有字符均为小写字母;保证所有的字符串长度都小于10,1 \leq n \leq 10^51≤n≤105)
- 解析:顺序排好的字符串,用二分查找第一个出现的字符,但是中间插入了很多“0”字符,中间搜索到0的时候,往左移动,找到最左边非0的位置。再做一般性比较。
1 | int searchLeftFirstChar(const vector<string> &table,const string &target) |
字符串的调整I
给定一个字符串chas[],其中只含有字母字符和“”字符,现在想把所有“”全部挪到chas的左边,字母字符移到chas的右边。完成调整函数。
1
2
3 qw**23
**qw23
- 从后往前排,用一个标记*,一个标记字符。
1 | int main() |
字符串的调整II
给定一个字符类型的数组chas[],chas右半区全是空字符,左半区不含有空字符。现在想将左半区的空格字符串替换成“%20”,假设chas右半区足够大,可以满足替换需要的空间,请完成替换函数。
1
2
3 a b c
a%20%20b%20%20%20%20c
解析:c++中的string a; cin >> a; 只能输入单字符串,因为它会以空白符作为退出;因此要读入一段句子,可以用
getline(cin, a)
;先遍历a计算出空白符的数目,然后知道了string变形后的大小,利用resize实现。然后从后面依次替换。
1 |
|
翻转字符串(1)
给定字符类型的数组chas,请在单词间做逆序调整。只要做到单词的顺序逆序即可,对空格的位置没有要求。
1
2
3 i am a student
i ma a tneduts
- 解析:
1 | void reverse(string &target) |
python: hehe,挺有意思的。
1 | chas = list(input().split()) |
翻转字符串(2)
给一个字符类型的数组chas和一个整数size,请把大小为size的左半区整体右移到右半区,右半区整体移动到左边。
1
2
3
4 3
abcdefg
defgabc
- 解析:双重反转,先对第一段反转,然后是第二段,最后全部翻转;
1 | int main() |
python:
1 | num = int(input()) |
方法2:
- 解析:画出来一个AB123456,把前两个交换到最后的实例;先交换一次:561234AB;之后得到最后的AB不用交换了;剩下561234;交换小的那部分得到341256;剩下3412;交换得到1234,左右部分都相等了交换结束。
1 | void exchange(string &s, int start, int end, int size) |
完美洗牌问题(1)
给定一个长度为偶数的数组arr,长度记为2N。前n个为左部分,后n个为右部分。arr可以表示为{L1,L_2…L{n-1},Ln,R_1,R_2…R{n-1},R_n }{L1,L2…Ln−1,Ln,R1,R2…Rn−1,Rn},请将数组调整成{ R_1,L_1,R_2,L_2,…R_n,L_n }{R1,L1,R2,L2,…Rn,Ln*}。
1
2
3
4
5 6
1 2 3 4 5 6
output:
4 1 5 2 6 3
- 解析:要求时间复杂度O(n),空间复杂度O(1)。
- 参考当数组的长度满足2*N == (3^k)-1时,才能使用公式替换;
因此对普通偶数长度的数组需要先切块;每块都左右部分交换之后,对该块利用公式替换;
1 |
|
完美洗牌问题(2)
给定一个数组arr,请将数组调整为依次相邻的数字,总是先<=、再>=的关系,并交替下去。比如数组中有五个数字,调整成[a,b,c,d,e],使之满足a<=b>=c<=d>=e。
1
2
3
4 6
1 2 3 4 5 6
output:
1 3 2 5 4 6
- 解析:1。先用非递归堆排序排好序,若数组长度为N是奇数,那么对【1,N-1】范围利用刚才的shuffle便是结果,如果N是偶数,则洗完拍之后,每两个数交换位置便是结果。
1 | //先排序再说 |
删除多余的字符得到字典序最小的字符串
给一个全是小写字母的字符串str,删除多余字符,使得每种字符只保留一个,并且让最终结果字符串字典序最小。
1
2
3 acbc
output:
abc
- 解析:先用一个map记录里面每个字符出现的数目,然后重新遍历字符串,同时减去map中对应字符出现值,当减为0 的时候,说明后续字符串中没有了这个字符;那么在当前遍历的串里找字符最小的作为串s的第一个元素;之后该定位字符的位置到减为0位置的元素在map中都加1,重新在该定位位置的下一处遍历,同时map中该定位字符不在考虑,设为-1。
1 | int main() |
数组中两个字符串的最小距离
给定一个字符串数组strs,再给定两个字符串str1和str2,返回在strs中str1和str2的最小距离,如果str1或str2为null,或不在strs中,返回-1。
1 输入包含有多行,第一输入一个整数n(1 \leq n \leq 10^5)(1≤n≤105),代表数组strs的长度,第二行有两个字符串分别代表str1和str2,接下来n行,每行一个字符串,代表数组strs (保证题目中出现的所有字符串长度均小于等于10)。
1
2
3
4
5
6
7
8
9
10 5
QWER 666
QWER
1234
qwe
666
QWER
output:
1
1 时间复杂度O(n),额外空间复杂度O(1)
- 解析:遍历一次,满足同时都在strs中的时候,记录下该次是否是最小距离。
1 |
|
字符串的转换路径问题
给定两个字符串,记为start和to,再给定一个字符串列表list,list中一定包含to,list中没有重复的字符串。所有的字符串都是小写的。规定start每次只能改变一个字符,最终的目标是彻底变成to,但是每次变成新字符串必须在list中存在。请返回所有的最短的变换路径(按照字典序最小的顺序输出)。
1 如果存在转换的路径,请先输出“YES”,然后按照字典序最小的顺序输出所有路径。如果不存在请输出“NO”。
1
2
3
4
5
6
7
8
9
10 8
abc cab
cab
acc
cbc
ccc
cac
cbb
aab
abb
1
2
3
4
5 YES
abc -> abb -> aab -> cab
abc -> abb -> cbb -> cab
abc -> cbc -> cac -> cab
abc -> cbc -> cbb -> cab
解析:
步骤1:把start加入list,根据list生成每一个字符串的nexts信息。nexts具体指的是如果只改变一个字符,
该字符串可能变成哪些字符串(它们应该包含在这n个串中,或者是start字符串,to字符串)。
步骤2:nexts表等于一张图,每个字符串相当于图中的一个点,nexts信息相当于邻居节点,用宽度优先遍历求出
每一个字符串到start的最短距离。
步骤3:从start开始深度优先搜索,保证每一步走到的字符串的距离(步骤2计算的)是逐渐增加的,不然不是一条
合理的路径,若到达了to,则记录下来。- 陷阱:传map或者vector之类的时候不要用
const
关键字,不然通过键索引出来结果会报错;
- 陷阱:传map或者vector之类的时候不要用
1 |
|
添加最少的字符让字符串变为回文字符串(1)
给定一个字符串str,如果可以在str的任意位置添加字符,请返回在添加字符最少的情况下,让str整体都是回文字符串的一种结果。
1
2
3 AB
output:
ABA
1 |
|
添加最少的字符让字符串变成回文串(2)
给定一个字符串str,再给定str的最长回文子序列字符串strlps, 请返回在添加字符最少的情况下,让str整体都是回文字符串的一种结果。进阶问题比原问题多了一个参数,请做到时间复杂度比原问题的实现低。
1 输出包含两行,第一行包含一个字符串代表str( 1 \leq length_{str} \leq 5000)(1≤lengthstr≤5000),第二行包含一个字符串,代表strips。
1
2 A1B21C
121
1 AC1B2B1CA
1 str=“A1B21C",strlps="121",返回“AC1B2B1CA”或者“CA1B2B1AC”,总之,只要是添加的字符数最少,只返回其中一种结果即可。
- 解析:必然是一种结果,substr本身在原来的str中,所以str生成的回文串必然包含它们,而且不用额外的添加了,那么str变成的回文串长度为 2 * str.size() - substr.size() ,对应substr来把str的前后字符按个放到res里。
1 |
|
括号字符串的有效性
给定一个字符串str,判断是不是整体有效的括号字符串(整体有效:即存在一种括号匹配方案,使每个括号字符均能找到对应的反向括号,且字符串中不包含非括号字符)。
1 输出一行,如果str是整体有效的括号字符串,请输出“YES”,否则输出“NO”。
- 解析:做括号判断,直接遍历一次,然后非有效字符直接返回false;用一个balance记录左右字符出现的次数;当右括号太多的时候直接返回false;最后看左右符号是否相等。
1 |
|
括号字符串的最长有效长度
给定一个括号字符串str,返回最长的能够完全正确匹配括号字符字串的长度。
1
2
3
4 (()())
6
())
2
1 时间复杂度O(n),额外空间复杂度O(n)。
解析:
1
2
3
4
5
6//dp[i]:str[0...i]中必须以str[i]结尾的最长有效字符串长度;
//str[i] == '('那么dp[i]=0;
//str[i] == ')',比如 (()()()),i - dp[i - 1] -1才到达第一个(符号的位置,发现匹配上;
//比如 ()(());也就是i - dp[i - 1] -1匹配为(()),此时第一对()也是有效考虑的情况了,所以加上它;
//比如 ()(()))时,i - dp[i - 1] -1 < 0,就不考虑有效了。
//
1 |
|