【算法设计与分析】理论 & 实验考核回顾

写在前面:

1:本文所有内容均为只作为参考,当年考题不可能重复近三年考过的内容。实验部分完整更新(因为可以自己带电脑且开卷考试),理论部分只更新记忆中的大题。

2:本人真的是一个算法菜鸡,但是个人认为这门课听了也对算法没什么提升,自学占大头。(希望真的能够2024年之前学会算法和数据结构,以及24年dp杯能榜上有名吧...)

3:后续可能会更新一个期末复习整理的大纲,由于csdn改版之后图片复制老是加载不了,所以如果要发出来的话挺耗时间的,之后没发就当我没说过这个事情(嗯)。


资料补档:

电子文件大纲(完整梳理版)更新:【算法设计与分析】期末汇总资源-CSDN文库

手写大纲更新:

 


实验:

1:

【问题描述】给定一个按值有序(升序)的N元整数数组A,采用折半查找法查找关键值k的位置,并给出查找的过程
【输入形式】

第一行:N

第二行:A[0], A[1], ... , A[N-1]

第三行:k
【输出形式】

第一行:k的位置(索引),若不存在则输出‘no’

第二行:查找的过程,每一次折半的中间(mid)位置的值,以逗号分隔。例如,1 2 3 4 5的中间位置为3,1 2 3 4的中间位置为2。
【样例输入】

样例1

11

2,5,8,11,15,16,22,24,27,35,50

22

样例2

11

2,5,8,11,15,16,22,24,27,35,50

10
【样例输出】

样例1

6

16,27,22

样例2

no

16,8,11
【样例说明】
【评分标准】必须使用折半法,其他方法不能得分。

#include <stdio.h>
#include <stdlib.h>

int main(){
	//input 
	int N;
	scanf("%d",&N);
	int *A=(int*)malloc(sizeof(int)*N);
	int i=0;
	for(i=0;i<N;i++){
		//cin>>A[i];
		scanf("%d",&A[i]);
	}
	int k;
	//cin>>k;
	scanf("%d",&k);
	
	//half search
	int left=0,right=N-1,mid;
	int cnt=0;
	int flag=0;
	while(left<=right){
		mid=(left+right)/2;
		
		if(k<A[mid]){
			right=mid;
		}
		else if(k>A[mid]){
			left=1+mid;
		}
		else{//k==mid
			flag=1;
			break;//found
		}
		
		if(cnt==0) //cout<<A[mid];
		{
			printf("%d",A[mid]);
		}
		else{
			printf(",%d",A[mid]);
		}
		//else cout<<","<<A[mid];
		cnt++;
	}
	
	if(flag=1){
		//cout<<mid;//output the number
		printf("%d",mid);
	}
	else{
		printf("no");
	}
	return 0;
}
//2 5 8 11 15 16 22 24 27 35 50

2:

【问题描述】一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少种跳法,并分析算法的时间复杂度,例如
n 为1 时只有一种跳法
n 为2 时只有两种跳法
【输入形式】输入一个整数n
【输出形式】n级的跳法数,整数m
【样例输入】

6
【样例输出】

13
【样例说明】

输入与输出均为整数
【答题要求】

要求在注释中首先解释求解思路,如果有递推关系,必须说明为什么是这样的关系,递推计算是通过什么道理建立起来的,否则不得分。
需要指出使用了所学过的什么方法,并明确写出算法的时间复杂度。仅使用蛮力法的求解将严重失分。

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
#define MAX 10000000


/*

用front、mid、rear存放暂态
类似用三个变量实现dp,使用过程中不断变表 
 
参考斐波那契数
跳上n阶梯子需要前面梯子做基础
若差一阶和f(n-1)相同
若差两阶f(n-2)相同

时间复杂度为O(N) 
*/ 
int fun(int n){
	if(n<2){
		return 1;
	}
	int front=1,mid=1,rear=1;
	for(int i=2;i<=n;i++){
		front=mid;
		mid=rear;
		rear=(front+mid)%MAX;
		//max为取余,防止数字过大 
	}
	return rear;
}

int main(){
	//input 
	int n;
	cin>>n;
	
	cout<<fun(n);
	return 0;
}

3:

【问题描述】

输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
【输入形式】

一个升序排序的数组以空格隔开,以及一个目标数字,换行输入
【输出形式】

如果存在数组中两个数字和为目标数字,则输出数字对;

如果存在多个满足条件的数字对,输出一对即可;

不存在则不输出;
【样例输入】

1 2 4 7 11 15

15

【样例输出】

4 11
【样例说明】

4+11=15
【评分标准】

时间复杂度必须为 O(n),否则酌情给分。

注释中要首先说明求解思路。

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

int main(){
	//输入 
	int n;//元素个数
	cin>>n;
	int *a=(int*)malloc(sizeof(int)*n);
	for(int i=0;i<n;i++){
		cin>>a[i];
	} 
	int target;
	cin>>target;
	
	//查找对应的元素 ,cnt可以用于估算时间复杂度 
	int flag=0,front=0,rear=n-1,cnt=0;
	//双指针,front指向从头开始的元素,rear指向从尾开始的元素
	while(front<rear){
		//序列非负的情况下,如果target始终大于起始值,则两数一定在前面 
		//但是好像没说非负
		/* 
		if(a[rear]>target){
			rear--;
			cnt++;
			continue;
		}*/
		
		//找到两数 
		if(a[front]+a[rear]==target){
			flag=1;
			cnt++;
			break;
		}
		
		//如果和偏大,则说明rear取大了 
		else if(a[front]+a[rear]>target){
			rear--;
			cnt++;
		}
		
		//如果和偏小,则说明front取小了 
		else{
			front++;
			cnt++;
		}
	}
	
	if(flag==1){
		cout<<a[front]<<" "<<a[rear];
	}
	//cout<<cnt;
	return 0;
} 
/*
6
1 2 4 7 11 15
15

4:

【问题描述】在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。例如
在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果。
【输入形式】整数数组,空格隔开
【输出形式】数对之差的最大值,一个数字
【样例输入】
2 5 8 19 3 6

【样例输出】

16
【样例说明】题目要求输出数对之差的最大值,即数字减去右边数字的值,不一定为数组中最大值和最小值的差。
【评分标准】要求设计时间和空间复杂度最低、代码最简洁的方法。性能越好得分越高。
如使用蛮力法求解得分最低。注释中要明确解释求解思路与所采用的方法。

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

int main(){
	//input 
	int n;
	cin>>n;
	int *a=(int*)malloc(sizeof(int)*n);
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	
	//特殊情况讨论 
	if(n==0){
		return 0;
	}
	if(n==2){
		cout<<a[1]-a[0];
		return 0;
	}
	
	//动态规划,maxD记录差值最大值,max记录从右侧开始的最大值 
	int maxD=0,max=a[n-1];
	for(int i=n-2;i>=0;i--){
		//前面一个数大于当前max 
		if(a[i]>max){
			max=a[i];//更新max 
		}
		//当前值小于max,判断差值大小 
		else{
			//如果max减去当前值比maxD大 
			if(max-a[i]>maxD){
				maxD=max-a[i];//更新maxD 
			}
		}
	}
	//时间复杂度为O(n),空间复杂度O(1) 
	
	cout<<maxD<<endl;
	return 0;
}

理论:

小题部分(填空+选择):

1:tsp的英文全称。

2:课件上出现过的概率算法的名字。

3:根据T(n-1)计算大O。

4:回溯法的TSP问题的解空间树采用了什么树。

5:L型骨牌的数目计算公式。

6:给出概率pi和时间ti,分析算法的时间复杂度。

7:大O、大Ω、大Θ哪个给出了上界。

【三】

3.1:给了一堆f(n)和g(n),包括绝对值、log对数、取整等,反正挺复杂的...,求阶相关的大O、大Ω、大Θ,并给出其中对应符号最大和最小的函数。

3.2:KMP的主要思想。

3.3:汉诺塔的伪代码。

3.4:根据问题规模和算法时间T(n),求解计算机在速度性能上翻倍之后且算法不变的情况下,能解决的问题规模为多少?

【四】

4.1:根据T(n-1)计算大Θ。

4.2:快排的伪代码,分析时间复杂度。

4.3:用贪心法算开车加油的最少次数(有n个加油站,初始的时候没油,给出了各加油站距离起始点的位置,油箱容量为m),给出具体的贪心策略,并分析时间复杂度。

猜你喜欢

转载自blog.csdn.net/m0_65787507/article/details/130875051