计算机算法设计与分析 期末复习笔记

1.算法复杂度的求解与分析:

https://blog.csdn.net/weixin_43510131/article/details/84237929?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162519159816780265479319%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=162519159816780265479319&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-3-84237929.pc_v2_rank_blog_default&utm_term=%E7%AE%97%E6%B3%95%E5%A4%8D%E6%9D%82%E5%BA%A6%E5%88%86%E6%9E%90%E6%80%8E%E4%B9%88%E6%B1%82&spm=1018.2226.3001.4450
常用的时间复杂度所耗费的时间从小到大依次是:
O(1) < O(logn) < (n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)

算法的空间复杂度的计算公式记作:S(n)=O(f(n)),其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数,也是一种“渐进表示法”,这些所需要的内存空间通常分为“固定空间内存”(包括基本程序代码、常数、变量等)和“变动空间内存”(随程序运行时而改变大小的使用空间)
https://blog.csdn.net/qq_17534301/article/details/82872357?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control
在这里插入图片描述
在这里插入图片描述
T(n)=O(f(n))
设语句1的频度为多少
依次类推 频度也是fn
然后Tn加起来 fn+起来 转化为O()

用常数1取代运行时间中的所有加法常数。 在修改后的运行次数函数中,只保留最高阶项。 如果最高阶项存在且不是1,则去除与这个项相乘的常数。
得到的最后结果就是大O阶

2.最长公共子序列

2.最长公共子序列

void LCSLength(int m,int n,char *x,char *y,int **c,int **b)
{
	int i,j;
	for(int i=1;i<=m;i++) c[i][0]=0;
	for(int i=1;i<=m;j++) c[0][i]=0;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=m;j++){
		if(x[i]=y[i]) 
		{
			c[i][j]=c[i-1][j-1];
			b[i][j]=1;
		}
		else if(c[i-1][j]>=c[i][j-1]){
			c[i][j]=c[i-1][j];
			b[i][j]=2;
		}
		else{
			c[i][j]=c[i][j-1]
			b[i][j]=3;
		}
}

void LCS(int i,int j,char *x,int **b)
{
	if(i==0 ||j==0) return;
	if(b[i][j]==1) {LCS(i-1,j-1,x,b)
	else if(b[i][j]==2) LCS(i-1,j,x,b)
	else LCS(i,j-1,x,b)

3.设计一个O(n2)的最长单调递增子序列的求解

#include<stdio.h>
int main() {
    int max = 0, count = 1,n = 7;
    int b, c;
    int a[] = { 2,1,4,7,8,-1,20 };
    for (int i = 0; i < n; i++) {
        b = a[i];
        for (int j = i + 1; j < n; j++) {
            if (b < a[j]) {
                b = a[j];
                count++;
            }
            else break;
        }
        if (max < count) {
            max = count;
            c = i;
        }
        count = 1;
    }
    printf("%d ",a[c]);
    b = a[c];
    for (int i = c + 1; i < n; i++) {
        if (b < a[i]) {
            b = a[i];
            printf("%d ", b);
        }
        else break;
    }
    return 0;
}


// Dynamic programming.
class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums.length == 0) return 0;
        int[] dp = new int[nums.length];
        int res = 0;
        Arrays.fill(dp, 1);
        for(int i = 0; i < nums.length; i++) {
            for(int j = 0; j < i; j++) {
                if(nums[j] < nums[i]) dp[i] = Math.max(dp[i], dp[j] + 1);
            }
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}


4.设计一个O(nlogn)的算法,求最长公共子序列

class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] tails = new int[nums.length];
        int res = 0;
        for(int num : nums) {
            int i = 0, j = res;
            while(i < j) {
                int m = (i + j) / 2;
                if(tails[m] < num) i = m + 1;
                else j = m;
            }
            tails[i] = num;
            if(res == j) res++;
        }
        return res;
    }
}


5.编辑距离:

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符 删除一个字符 替换一个字符

 for (int i = 0; i < dp.size(); i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j < dp[0].size(); j++) {
            dp[0][j] = j;
        }

        for (int i = 1; i < dp.size(); i++) {
            for (int j = 1; j < dp[i].size(); j++) {
                dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1;
                if (word1[i - 1] == word2[j - 1]) {
                    dp[i][j] = min(dp[i][j], dp[i - 1][j - 1]);
                }
            }


6.租用游艇

在这里插入图片描述

#include<iostream>
#include<cmath>
using namespace std;
int a[201][201],i,j,n,dp[201];
int main(){
	cin>>n;
	for(i=1;i<n;i++){
		for(j=i+1;j<=n;j++)
			cin>>a[i][j];
		dp[i]=1e9;//初始化数组dp,使它
	}
	for(i=n-1;i>=1;i--)//跑n上流的中转站
		for(j=i+1;j<=n;j++)//跑i下流的所有中转站
			dp[i]=min(dp[i],a[i][j]+dp[j]);//记录
	cout<<dp[1];
	return 0;
}

7.字符串比较问题

对于长度相同的 2 个字符串 A 和 B,其距离定义为相应位置字符距离之和。2 个非空格字符的距离是它们的 ASCII
码之差的绝对值。空格与空格的距离为 0;空格与其它字符的距 离为一定值 k。

在一般情况下,字符串 A 和 B 的长度不一定相同。字符串 A 的扩展是在 A 中插入若干 空格字符所产生的字符串。在字符串 A 和 B
的所有长度相同的扩展中,有一对距离最小的 扩展,该距离称为字符串 A 和 B 的扩展距离。 对于给定的字符串 A 和
B,试设计一个算法,计算其扩展距离。

数据输入: 第 1 行是字符串 A;第 2 行是字符串 B。第 3 行是空格与其它字符的距离定值 k ————————————————

import java.util.Scanner;
/*
val(i,j): 字符串A和B的子串A[1..i]和B[1..j]的扩展距离
val(i,j)=min{val(i-1,j)+k, val(i,j-1)+k, val(i-1,j-1)+dist(ai, bj)}
*/
public class ZiFuChuanBiJiao {
    private static String str1,str2;
    private static int len1,len2;
    private static int[][] val;
    private static int k;//空格与其他字符的距离定值


    private static int MAX = 100000;

    public static void main(String[] args){

        Scanner input = new Scanner(System.in);

        while (true){
            str1 = input.next();
            str2 = input.next();
            k = input.nextInt();

            len1 = str1.length();
            len2 = str2.length();
            val = new int[len1+1][len2+1];
            val[0][0] = 0;

            comp();
        }
    }

    private static void comp(){
        int i,j,tmp;

        for(i=0; i<=len1; i++)
            for(j=0; j<=len2; j++)
                if(i+j > 0){
                    val[i][j] = MAX;
                    if(i*j>0 && (tmp=(val[i-1][j-1])+dist(str1.charAt(i-1),str2.charAt(j-1))) < val[i][j])
                        val[i][j] = tmp;
                    if(i>0 && (tmp=(val[i-1][j])+dist(str1.charAt(i-1),' ')) < val[i][j])
                        val[i][j] = tmp;
                    if(j>0 && (tmp=(val[i][j-1])+dist(str2.charAt(j-1),' ')) < val[i][j])
                        val[i][j] = tmp;
                }

        System.out.println(val[len1][len2]);
    }

    private static int dist(char a, char b){
        if(a ==' ' || b == ' ')
            return k;
        else
            return Math.abs(a-b);
    }
}

8.活动安排问题:

设有n个活动的集合E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si
<fi 。如果选择了活动i,则它在半开时间区间[si, fi)内占用资源。若区间[si, fi)与区间[sj,
fj)不相交,则称活动i与活动j是相容的。也就是说,当si≥fj或sj≥fi时,活动i与活动j相容。

#include <iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
typedef struct{
   int s;//活动开始时间
   int f;//活动结束时间
   int index;//活动序号,视情况而定是否用上
}action;
//根据活动结束时间进行非降序排序
void sort_action(action a[],int n)
{   int i,j;
    action temp;
    for(i=1;i<=n;i++)
    for(j=1;j<=n-i;j++)
    {
        if(a[j].f>a[j+1].f)
        {
            temp=a[j];
            a[j]=a[j+1];
            a[j+1]=temp;
        }
    }
}

int main()
{
    int n;//输入n代表有n个活动
    cin>>n;
    action a[n+1];
    for(int i=1;i<=n;i++){
        cin>>a[i].s>>a[i].f;
        a[i].index=i;//构造活动结构体数组
    }
    sort_action(a,n);//冒泡排序
    bool b[n+1];
    int num=1;
    b[1]=true;//第一个活动必定安排
    int pretime=a[1].f;
    for(int i=2;i<=n;i++){
        if(a[i].s >= pretime){
            b[i]=true;
            num++;//a[i]活动安排上
            pretime=a[i].f;//更新pretime
        }else{
            b[i]=false;
        }
    }
    //输出相容的最大活动数目
    cout<<num<<endl;
    //根据情况是否输出活动序号
    for(int i=1;i<=n;i++){
        if(b[i]) cout<<a[i].index<<" ";
    }
    return 0;
}

9.最小生成树

https://blog.csdn.net/learning_tortosie/article/details/80164938?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162521138616780357246933%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162521138616780357246933&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-1-80164938.first_rank_v2_pc_rank_v29&utm_term=%E7%AE%97%E6%B3%95%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%88%86%E6%9E%90%E4%B8%AD%E7%9A%84%E6%9C%80%E5%B0%8F%E7%94%9F%E6%88%90%E6%A0%91&spm=1018.2226.3001.4187
Prim:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mmax 100
#define maxt 100000000
int v[mmax][mmax];
 
void Prim(int n){
	int low[mmax];// 
	int clo[mmax];
	bool s[mmax];//判断该节点是否在S中 
	s[1]=true;
	for(int i=2;i<=n;i++){
		low[i]=v[1][i];//初始化 
		clo[i]=1;
		s[i]=false;
	}
	for(int i=1;i<n;i++){//对剩余的n-1个顶点进行操作 ,此处的i并无实际意思,只是起到一个记录变量的作用 
		int min=maxt;
		int j=1;
		for(int k=2;k<=n;k++)//从V-S中找到S中边权最小的节点 
			if((low[k]<min)&&(!s[k])){
				min=low[k];
				j=k;
			}
			cout<<j<<" "<<clo[j]<<":"<<low[j]<<endl;
			s[j]=true;
			for(int k=2;k<=n;k++){//调整low中的值,加入j节点之后,使得两个集合中的距离最小 
				if((v[j][k]<low[k])&&(!s[k])){
					low[k]=v[j][k];
					clo[k]=j;
				}
			}
		
	}
} 
 
int main()
{
	int n,m;//n vertexs and m edges
	cin>>n>>m;
	int ii,jj,tt;
	for(int i=0;i<=n;i++){
		for(int j=0;j<=n;j++)
		v[i][j]=maxt;
	}
	for(int i=0;i<m;i++){
		cin>>ii>>jj>>tt;
		v[ii][jj]=tt;
		v[jj][ii]=tt;
	}
	Prim(n);
	return 0;
}
 
//6 10
//1 2 6
//1 4 5
//1 3 1
//2 3 5
//2 5 3
//3 4 5
//3 5 6
//3 6 4
//4 6 2
//5 6 6

krusal:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,tot=0,k=0;//n端点总数,m边数,tot记录最终答案,k已经连接了多少边 
int fat[200010];//记录集体老大 
struct node
{
	int from,to,dis;//结构体储存边 
}edge[200010];
bool cmp(const node &a,const node &b)//sort排序(当然你也可以快排) 
{
	return a.dis<b.dis;
}
int father(int x)//找集体老大,并查集的一部分 
{
	if(fat[x]!=x)
	return father(fat[x]);
	else return x;
}
void unionn(int x,int y)//加入团体,并查集的一部分 
{
	fat[father(y)]=father(x);
}
int main()
{
	scanf("%d%d",&n,&m);//输入点数,边数 
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].dis);//输入边的信息 
	}
	for(int i=1;i<=n;i++) fat[i]=i;//自己最开始就是自己的老大 (初始化) 
	sort(edge+1,edge+1+m,cmp);//按权值排序(kruskal的体现) 
	for(int i=1;i<=m;i++)//从小到大遍历 
	{
		if(k==n-1) break;//n个点需要n-1条边连接 
		if(father(edge[i].from)!=father(edge[i].to))//假如不在一个团体 
		{
			unionn(edge[i].from,edge[i].to);//加入 
			tot+=edge[i].dis;//记录边权 
			k++;//已连接边数+1 
		}
	}
	printf("%d",tot);
	return 0;
}

10.汽车加油问题:

一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,指出应
在哪些加油站停靠加油,使沿途加油次数最少。对于给定的n(n <= 5000)和k(k <= 1000)个加油站位置,编程计算最少加油次数。并证明算法能产生一个最优解。
要求:
输入:第一行有2个正整数n和k,表示汽车加满油后可行驶n公里,且旅途中有k个加油站。接下来的1 行中,有k+1 个整数,表示第k个加油站与第k-1 个加油站之间的距离。第0 个加油站表示出发地,汽车已加满油。第k+1 个加油站表示目的地。
输出:输出编程计算出的最少加油次数。如果无法到达目的地,则输出”NoSolution”。

思路:
汽车行驶过程中,应走到自己能走到并且离自己最远的那个加油站,在那个加油站加油后再按照同样的方法贪心

具体算法:
先检测各加油站之间的距离,若发现其中有一个距离大于汽车加满油能跑的距离,则输出no solution
否则,对加油站间的距离进行逐个扫描,并且累加记录距离,尽量选择往远处走,不能走了,即当累加距离大于n时,就加油一次(num++),最终统计


#include <iostream>
using namespace std;
void greedy(int d[],int n,int k) {//汽车加满油之后可以行驶n千米,沿途有k个加油站
    int num = 0;
    for(int i = 0;i <= k;i++) {
        if(d[i] > n) {//加油站之间的距离
            cout<<"no solution\n"<<endl;
            break;
        }
    }
    for(int i = 0,sum = 0;i <= k;i++) {
        sum += d[i];//加油站间距离相加
        if(sum > n) {//车无法达到第i个加油站,加油一次,s等于从加过油的地方开始计
            num++;
            sum = d[i];
        }
    }
    cout<<num<<endl;
}
 
int main() {
    int i,n,k;
    int d[1000];
    cout<<"请输入汽车加满油可行驶千里数以及加油站数量"<<endl;
    cin>>n>>k;
    cout<<"输入第k个加油站和第k-1个加油站之间的距离"<<endl;
    for(i = 0; i <= k; i++)
        cin>>d[i];
    greedy(d,n,k);
}

11.批处理作业调度

https://blog.csdn.net/qian2213762498/article/details/79420060?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162531333716780261957961%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=162531333716780261957961&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-79420060.first_rank_v2_pc_rank_v29&utm_term=%E6%89%B9%E5%A4%84%E7%90%86%E4%BD%9C%E4%B8%9A%E8%B0%83%E5%BA%A6&spm=1018.2226.3001.4187

12.n皇后问题

130页
非递归的意思差不多是一个一个格子+0走的

13.0-1背包

132

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 计算机算法设计分析计算机科学与技术专业的一门重要课程,该课程旨在培养学生解决复杂问题的能力,提高算法设计分析的能力。复习该课程的期末考试,我建议可以从以下几个方面进行复习: 首先,复习算法的基本知识。包括递归与分治策略、动态规划、贪心算法、回溯算法等常见算法的基本原理和代码实现方法。 其次,深入理解常见的时间复杂度和空间复杂度分析方法,熟悉不同算法的优缺点,并能在不同问题场景下选择合适的算法。 然后,重点复习常见的排序算法和查找算法,如冒泡排序、插入排序、选择排序、快速排序、堆排序等,以及线性查找、二分查找等。 另外,复习算法,包括图的表示方法、图的遍历算法、最短路径算法(Dijkstra算法、Floyd-Warshall算法)和最小生成树算法(Prim算法、Kruskal算法)等。 最后,通过做一些实例题和习题,加深对算法的理解和应用能力,提高解题的效率。 在复习过程中,可以参考csdn等一些相关的学习资源,查找更多的学习资料和参考题目,加深对算法的认识。同时也可以结合自己的课堂笔记、教材和讲义,全面复习和总结。 总之,计算机算法设计分析期末考试的复习需要全面、系统地复习相关算法和数据结构的知识,并能够熟练应用到实际问题中。通过不断的实践和练习,提高解题的能力和效率。 ### 回答2: 计算机算法设计分析期末考试复习题介绍了一些重要的算法和数据结构,学生们可以通过复习这些题目来准备考试。以下是一些常见的题型和解答思路: 1. 排序算法:考察对常见排序算法的理解和分析。如快速排序、归并排序、堆排序等。需要掌握它们的时间复杂度、原理和实现方式,以及它们在不同场景下的优劣势。 2. 搜索算法:考察对常见搜索算法的掌握程度。如深度优先搜索(DFS)、广度优先搜索(BFS)、二分查找等。需要了解它们的原理、如何实现以及最优应用场景。 3. 图算法:考察对图算法的熟悉程度。如最短路径算法(如Dijkstra算法、Floyd-Warshall算法)、最小生成树算法(如Prim算法、Kruskal算法)等。需要了解它们的原理、时间复杂度和应用场景。 4. 动态规划:考察对动态规划算法的理解和应用。需要掌握动态规划的基本概念、状态转移方程的建立和求解。重点理解背包问题、最长公共子序列等常见问题的动态规划解法。 5. 数据结构:考察对常见数据结构的掌握程度。如数组、链表、栈、队列、二叉树、图等。需要了解它们的基本操作、特性、应用场景以及在算法中的使用方法。 在复习期间,建议学生们重点关注基础概念的理解、算法原理的掌握以及常见题目的解题技巧。同时,通过做大量的练习题来提升自己的算法设计分析能力。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值