1. (2014)计算两个字符串的编辑距离
问题定义
把两个字符串变成相同的三个基本操作定义如下:
- 修改一个字符(如把a 变成b)
- 增加一个字符(如abed 变成abedd)
- 删除一个字符(如jackbllog 变成jackblog)
针对于jackbllog 到jackblog 只需要删除一个或增加一个l 就可以把两个字符串变为相同。把这种操作需要的最小次数定义为两个字符串的编辑距离L。
编写程序计算指定文件中字符串的距离。输入两个长度不超过512 字节的ASCII 字符串,在屏幕上输出字符串的编辑距离。
输入样例
Hello world!
Hello wortd!
输出样例
1
分析: 和最长公共子串极为相似,具体为
d
p
[
i
]
[
j
]
=
{
d
p
[
i
−
1
]
[
j
−
1
]
s
t
r
1
[
i
]
=
s
t
r
2
[
j
]
min
{
d
p
[
i
−
1
]
[
j
−
1
]
+
1
,
d
p
[
i
−
1
]
[
j
]
+
1
,
d
p
[
i
]
[
j
−
1
]
+
1
}
s
t
r
1
[
i
]
≠
s
t
r
2
[
j
]
dp[i][j] = \begin{cases} dp[i-1][j-1] & str1[i] = str2[j] \\ \min\{dp[i-1][j-1]+1,dp[i-1][j]+1,dp[i][j-1]+1\} & str1[i] \neq str2[j] \end{cases}
dp[i][j]={dp[i−1][j−1]min{dp[i−1][j−1]+1,dp[i−1][j]+1,dp[i][j−1]+1}str1[i]=str2[j]str1[i]=str2[j]
注: str1[i] != str2[j]时,三种情况的解释如下:
- alter str1[i]、str2[j]
- delete str1[i] or add str2[j]
- delete str2[j] or add str1[i]
初试化条件为: d p [ 0 ] [ 0 ] = 0 , d p [ 0 ] [ j ] ( j ∈ [ 1 , m ] ) = j , d p [ i ] [ 0 ] ( i ∈ [ 1 , n ] ) = i dp[0][0] = 0,dp[0][j] (j \in[1,m]) = j, dp[i][0] (i\in[1,n]) = i dp[0][0]=0,dp[0][j](j∈[1,m])=j,dp[i][0](i∈[1,n])=i
2 . (2015)正方形个数
给出长方形的长和宽,每次从长方形里撕去最大的正方形,输出最后能得到多少正方形
void square_cnt(int l, int w) {
int cnt = 0;
while (l > w) {
l -= w;
cnt++;
if (l < w) swap(l,w);
}
printf("%d", cnt + 1); //l=w(+1)
}
3 . (2015)优先级队列的实现
ADD N P:往队列里加入id为N的优先级为P的任务
NEXT:输出下一个最高优先级的任务的id,如果优先级相同输出id小的任务,若队列中没有任务输出-1
REMOVE N:移除id为N的任务
COUNT:输出队列中的任务数量
分析: 刚学会了priority_queue就拿来用用,但是有个缺陷就是REMOVE时要O(pq.size())的复杂度,不过因为不清楚具体数据量,也不会其它方法,就先这样啦,核心代码如下:
struct process{
int id;
int p;
process(int a = 0, int b = 0) :id(a), p(b) {} //init
};
struct cmp {
bool operator() (process p1, process p2) {
if (p1.p == p2.p) {
return p1.id > p2.id; //优先级相同则id小的在前
}
return p1.p < p2.p; //优先级大的在前
}
};
//priority_queue<int> qi; //后两个参数缺省,优先队列就是大顶堆,队头元素最大
priority_queue<process, vector<process>, cmp> pq;
4 . (2016) Huffman编码长度
给定一个字符串,求哈夫曼编码的长度
核心步骤如下:
- f1数组记录字符出现频度(hash, 用于建树),然后排序(升序),并设置对应的level数组(初始为0,用于最后的编码长度计算)以及f2(cnt统计个数)数组(合并时的新结点数组, 升序排列)
- 从f1和f2中取得最小的两个结点(最多从4个结点中选择), 记cnt1(-1)和cnt2(-1)为当前指示下标, 从f1中取得几个结点, cnt1就加几, 然后level[0~cnt1]增1, 合并的新结点进入f2,直到f1中结点已遍历完且f2仅剩一个结点未处理
- 对level[i]*f1[i] (0~n-1)求和,即为最终Huffman编码长度
5 . (2014) Hanoi塔
把A 柱上的n 个金片,搬动到C 柱(中间可以使用B 柱),使得搬动的次数最少。输入金片的个数n(1<=n<=64),输出总搬动次数,以及最后100 次搬动。如果搬动次数小于等于100 则全部输出;每个搬动占一行,加上这是第几次搬动的数字和”:”,格式见示例。
输入样例
2
输出样例
3
1:A->B
2:A->C
3:B->C
分析: 不是很明白。。。先贴下非递归的链接,以后抽时间补充
http://blog.sina.com.cn/s/blog_48e3f9cd01000474.html
6 . (2013) 字符串匹配
对于主串M和模式串P,找到P在M中出现的所有子串的第一个字符在P中的位置。P中第一个字符所在的位置为0。首行
的数字表示有多少组字符串。
[输入及示例]
2
ababababa
ababa
aaa
aa
[输出及示例]
0 2 4
0 1
(相邻位置之间用一个空格隔开)
#include <cstdio>
#include <iostream>
#include <string> //string
using namespace std;
void Solve(string m, string p) {
string m1;
int pos = m.find(p);
int len = m.size();
int pos1;
printf("%d", pos);
//原字符串上截取子串时用另一个变量保存
while (len - pos - 1 >= p.size()) {
m1 = m.substr(pos + 1, len - pos - 1);
pos1 = m1.find(p);
if (pos1 != string::npos) {
pos += (pos1 + 1);
printf(" %d", pos);
}
else break;
}
printf("\n");
}
int main() {
string m, p;
int n;
scanf("%d", &n);
while (n--) {
cin >> m >> p;
Solve(m, p); //至少匹配一个
}
return 0;
}