复旦研究生历年机试试题

1. (2014)计算两个字符串的编辑距离
问题定义
把两个字符串变成相同的三个基本操作定义如下:

  1. 修改一个字符(如把a 变成b)
  2. 增加一个字符(如abed 变成abedd)
  3. 删除一个字符(如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[i1][j1]min{dp[i1][j1]+1dp[i1][j]+1dp[i][j1]+1}str1[i]=str2[j]str1[i]=str2[j]
注: str1[i] != str2[j]时,三种情况的解释如下:

  1. alter str1[i]、str2[j]
  2. delete str1[i] or add str2[j]
  3. 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 qi; //后两个参数缺省,优先队列就是大顶堆,队头元素最大
priority_queue, cmp> pq;

4 . (2016) Huffman编码长度
给定一个字符串,求哈夫曼编码的长度
核心步骤如下:

  1. f1数组记录字符出现频度(hash, 用于建树),然后排序(升序),并设置对应的level数组(初始为0,用于最后的编码长度计算)以及f2(cnt统计个数)数组(合并时的新结点数组, 升序排列)
  2. 从f1和f2中取得最小的两个结点(最多从4个结点中选择), 记cnt1(-1)和cnt2(-1)为当前指示下标, 从f1中取得几个结点, cnt1就加几, 然后level[0~cnt1]增1, 合并的新结点进入f2,直到f1中结点已遍历完且f2仅剩一个结点未处理
  3. 对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 
#include 
#include  //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;
}

你可能感兴趣的:(------算,法------)