数据结构和算法(1):开始

news2024/11/26 22:43:21

算法概述

所谓算法,即特定计算模型下,旨在解决特定问题的指令序列
输入 待处理的信息(问题)
输出 经处理的信息(答案)
正确性 的确可以解决指定的问题
确定性 任一算法都可以描述为一个由基本操作组成的序列
可行性 每一基本操作都可实现,且在常数时间内完成
有穷性 对于任何输入,经有穷次基本操作,都可以得到输出

程序未必是算法,例如发生死循环或者栈溢出时。

算法在满足基本要求时,最重要的是:速度尽可能快,存储空间尽可能少(效率)

计算模型

两个主要方面:
1.正确性:算法功能与问题要求一致?
2.成本:运行时间 + 存储空间

计算成本: T ( n ) = max ⁡ { T ( P )   ∣   ∣ P ∣ = n } T(n)=\max \{T(P) \space \boldsymbol | \space |P| = n \} T(n)=max{T(P)  P=n} 遵守最坏情况分析原则。

特定问题,不同算法下,需要抽象出一种理想的平台或模型,不再依赖于种种具体因素,从而直接准确地描述、测量并评价算法。

渐进复杂度

随着问题规模地增长,运算成本增大
T ( n ) = O ( f ( n ) )  if  ∃   c > 0 , n ≫ 2 , T ( n ) < c ⋅ f ( n ) T(n) = \mathcal O(f(n)) \space \text{if } \exists \space c>0,n\gg 2, T(n)<c\cdot f(n) T(n)=O(f(n)) if  c>0,n2,T(n)<cf(n)

T ( n ) T(n) T(n) 相比, f ( n ) f(n) f(n)更为简洁,但依然反应前者地增长趋势:

常系数可忽略: O ( f ( n ) ) = ( c × f ( n ) ) \mathcal O(f(n)) = (c \times f(n)) O(f(n))=(c×f(n))
低次项可忽略: O ( n a + n b ) = O ( n a ) , a > b > 0 \mathcal O(n^a+n^b)=\mathcal O(n^a),a>b>0 O(na+nb)=O(na)a>b>0
在这里插入图片描述
1.常数复杂度为: O ( 1 ) \mathcal O(1) O(1)
算法不含转向(循环、调用、递归等),必顺序执行即复杂度为 O ( 1 ) \mathcal O(1) O(1)

2.对数复杂度为: O ( log ⁡ n ) \mathcal O(\log n) O(logn)
∀ c > 0 , l o g ( n ) = O ( n c ) \forall c>0,log(n)=\mathcal O(n^c) c>0,log(n)=O(nc),因此对数复杂度无限接近于常数

3.多项式复杂度: O ( n c ) \mathcal O(n^c) O(nc)

4.指数复杂度: O ( a n ) \mathcal O(a^n) O(an)
计算成本增长极快,通常认为不可以接受

复杂度增长速度
在这里插入图片描述

复杂度分析

算法分析的两个主要任务 = 正确性(不变性×单调性) + 复杂度

C++ 等高级语言的基本指令,均等效于常数条 RAM 的基本指令;在渐进意义下,两者相当。

复杂度分析的主要方法:
1.迭代:级数求和;
2.递归:递归追踪 + 递推方程;

实例:冒泡排序

问题:给定 n 个整数,将它们按(非降)序排列
观察:有序/无序序列中,任意/总有一对相邻元素顺序/逆序
思路:(扫描交换)依次比较每一个相邻元素,如果必要,交换之,若整躺扫描都没有进行交换,则排序完成;否则,再做一趟扫描交换。

void bubblesort(int A[],int n){
	for(bool sorted = false; sorted = !sorted; n--){	// 逐躺扫描交换,直至完全有序
		for(int i = 1; i< n; i++){	// 自左向右,逐对检查A[0,n)内各相邻元素
			if(A[i-1]>A[i]){	// 若逆序,则
				swap(A[i-1], A[i]);	//令其互换,同时
				sorted = false; //清楚(全局)有序标志	
			}
		}
	}
}

不变性:经过 k 轮扫描交换后,最大的 k 个元素必然就位;
单调性:经过 k 轮扫描交换后,问题规模缩减至 n-k;
正确性:经过最多 n 躺扫描后,算法必然终止,且能正确解答。

迭代与递归

递归跟踪分析:检查每个递归实例,累计所需时间(调用语句本身,计入对应的子实例),其总和即算法执行时间。

实例:数组求和(二分递归)

int sum(int A[], int lo, int hi){	//区间范围A[lo, hi]
	if(lo == hi) return A[lo];	//base case
	int mi = (lo + hi) >> 1;	//右移一位,相当于除以2 只有正数适用,而负数不适用
	return sum(A, lo, mi) + sum(A, mi+1, hi);
}	//入口形式为 sum(A,0,n-1)

master theorem

在这里插入图片描述

动态规划

实例:Fibonacci 序列

F ( 1 ) = 1 , F ( 2 ) = 1 , F ( n ) = F ( n − 1 ) + F ( n − 2 ) ( n > = 3 , n ∈ N ∗ ) F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*) F(1)=1F(2)=1,F(n)=F(n1)+F(n2)(n>=3nN)

计算Fibonacci数列的第n项(迭代版):O(n)

__int64 fibI ( int n ) { 
   __int64 f = 1, g = 0; //初始化:fib(-1)、fib(0)
   while ( 0 < n-- ) { g += f; f = g - f; } //依据原始定义,通过n次加法和减法计算fib(n)
   return g; //返回
}

计算Fibonacci数列的第n项(二分递归版):O(2^n)

__int64 fib ( int n ) { 
   return ( 2 > n ) ?
          ( __int64 ) n //若到达递归基,直接取值
          : fib ( n - 1 ) + fib ( n - 2 ); //否则,递归计算前两项,其和即为正解
}

计算Fibonacci数列第n项(线性递归版):O(n)

__int64 fib ( int n, __int64& prev ) { //入口形式fib(n, prev)
   if ( 0 == n ) //若到达递归基,则
      { prev = 1; return 0; } //直接取值:fib(-1) = 1, fib(0) = 0
   else { //否则
      __int64 prevPrev; prev = fib ( n - 1, prevPrev ); //递归计算前两项
      return prevPrev + prev; //其和即为正解
   }
} //用辅助变量记录前一项,返回数列的当前项,O(n)
//Fib.h
using Rank = unsigned int;

class Fib { //Fibonacci数列类
private:
   Rank f, g; //f = fib(k - 1), g = fib(k)。均为int型,很快就会数值溢出
public:
   Fib ( Rank n ) //初始化为不小于n的最小Fibonacci项
   { f = 1; g = 0; while ( g < n ) next(); } //fib(-1), fib(0),O(log_phi(n))时间
   Rank get()  { return g; } //获取当前Fibonacci项,O(1)时间
   Rank next() { g += f; f = g - f; return g; } //转至下一Fibonacci项,O(1)时间
   Rank prev() { f = g - f; g -= f; return g; } //转至上一Fibonacci项,O(1)时间
};

//main.c
#include<ctime>
#include<iostream>
using namespace std;

#include "Fib.h"

__int64  fibI ( int n ); //迭代版
__int64  fib ( int n ); //二分递归版
__int64  fib ( int n, __int64& f ); //线性递归版

int main ( int argc, char* argv[] ) { //测试FIB
// 检查参数
   if ( 2 > argc ) { fprintf ( stderr, "Usage: %s <Rank>\n", argv[0] ); return 1; }
   int n = atoi ( argv[1] );
// 依次计算Fibonacci数列各项
   printf ( "\n------------- class Fib -------------\n" );
   Fib f ( 0 );
   for ( int i = 0; i < n; i++, f.next() )
      printf ( "fib(%2d) = %d\n", i, f.get() );
   for ( int i = 0; i <= n; i++, f.prev() )
      printf ( "fib(%2d) = %d\n", n - i, f.get() );
   printf ( "\n------------- Iteration -------------\n" );
   for ( int i = 0; i < n; i++ )
      printf ( "fib(%2d) = %22I64d\n", i, fibI ( i ) );
   printf ( "\n------------- Linear Recursion -------------\n" );
   for ( int i = 0; i < n; i++ ) {
      __int64 f;
      printf ( "fib(%2d) = %22I64d\n", i, fib ( i, f ) );
   }
   printf ( "\n------------- Binary Recursion -------------\n" );
   for ( int i = 0; i < n; i++ )
      printf ( "fib(%2d) = %22I64d\n", i, fib ( i ) );
   return 0;
}

实例:LCS:最长公共子序列

两个字符串中找到最长的子序列,这里明确两个含义:
1.子串:表示连续的一串字符 。
2.子序列:表示不连续的一串字符。

1.两个字符串具有相同尾序,那么同时去掉两者的尾序,不影响它们的距离
2.如果 A 和 B 是不同的符号 ( A ≠ B A≠B A=B),则 L C S ( X A , Y B ) LCS(X^A,Y^B) LCS(XA,YB) 是以下两者的最大者: L C S ( X A , Y ) , L C S ( X , Y B ) LCS(X^A,Y), LCS(X,Y ^B) LCS(XA,Y),LCS(X,YB) ,适用于所有字符串 X 、 Y X、Y XY

给定两个字符串S1和S2,我们需要找到一个最长的子序列,该子序列同时出现在S1和S2中。这个子序列不要求在原字符串中是连续的,但在原字符串中的相对顺序必须与原字符串中的顺序相同。

举例说明:

假设有两个字符串:
S1 = “ABCBDAB”
S2 = “BDCAB”

它们的一个最长公共子序列是"BCAB",它在两个字符串中都出现,而且是最长的。

LCS问题的目标是找到这个最长的公共子序列的长度以及可能的子序列之一。在动态规划中,可以使用一个二维表格来解决这个问题,表格中的值表示两个字符串在不同位置的字符之间的LCS长度。

通过解决LCS问题,我们可以解决许多实际应用,如文本比对、版本控制、DNA序列比对等。这个问题在算法设计和字符串处理中具有重要性。

#include <iostream>
#include <vector>
#include <string>

using namespace std;

string longestCommonSubsequence(string s1, string s2) {
    int m = s1.length();
    int n = s2.length();
    
    // 创建DP表,初始化为0
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
    
    // 填充DP表
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (s1[i - 1] == s2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    
    // 回溯构建最长公共子序列
    string lcs = "";
    int i = m, j = n;
    while (i > 0 && j > 0) {
        if (s1[i - 1] == s2[j - 1]) {
            lcs = s1[i - 1] + lcs;
            i--;
            j--;
        } else if (dp[i - 1][j] > dp[i][j - 1]) {
            i--;
        } else {
            j--;
        }
    }
    
    return lcs;
}

int main() {
    string s1 = "ABCBDAB";
    string s2 = "BDCAB";
    
    string result = longestCommonSubsequence(s1, s2);
    
    cout << "Longest Common Subsequence: " << result << endl;
    
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/969310.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot核心原理与实践

第一章、SpringBoot简介 1、入门案例 2、官网创建压缩包程序 注意使用的版本pom文件中java --> 1.8、 springboot --> 2.5.0 3、SpringBoot快速启动 运行程序--找引导类 换技术、加技术--加starter 第二章、基础配置 1、配置文件格式 《1、端口号配置》 《2、将目录文…

React原理 - React Hooks

目录 扩展学习资料 React Hooks 编写函数组件 Hooks使命 Hooks解决了什么问题 Hooks原理 useState源码解析 mountState源码解析 Hooks应用 Hooks 实践 倒计时组件 练习 扩展学习资料 名称 链接 React Hooks 官方文档 Introducing Hooks – React useEffect 完整…

PYTHON知识点学习-列表和元组

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由 Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

把一般数据转换成因子数据格式,做单因子、债券对历史数据回测+获取curl命令+垃圾数据转换成标准行情数据(bardata)

下载curl软件&#xff0c;地址&#xff1a; curl for Windows for 64-bit下载好后解压到文件夹&#xff0c;将里面的bin文件添加到环境变量中&#xff0c;bon文件地址为&#xff1a;C:\Users\59980\curl-8.2.1_7-win64-mingw\bin 打开cmd&#xff0c;输入curl --help,出现下…

软考:中级软件设计师:程序语言基础:表达式,标准分类,法律法规,程序语言特点,函数传值传址

软考&#xff1a;中级软件设计师:程序语言基础&#xff1a;表达式 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都…

ssm民宿管理系统源码和论文

ssm民宿管理系统源码和论文110 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&…

SSM整合~

构建并配置项目&#xff1a; 第一步&#xff1a;创建maven项目 第二步&#xff1a;配置pom.xml文件 设置打包方式&#xff1a; <packaging>war</packaging>设置版本号为自定义属性&#xff1a; <properties><!--将版本号通过自定义属性配置--><…

跨站请求伪造(CSRF)攻击与防御原理

跨站请求伪造&#xff08;CSRF&#xff09; 1.1 CSRF原理 1.1.1 基本概念 跨站请求伪造&#xff08;Cross Site Request Forgery&#xff0c;CSRF&#xff09;是一种攻击&#xff0c;它强制浏览器客户端用户在当前对其进行身份验证后的Web 应用程序上执行非本意操作的攻击&a…

差异化竞争阵地的所在【周技术进阶】-从BS 项目C#最基础截取字符串方法开始

效果 代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace ConsoleAppNumberOneHelloWorld {class Program{static void Main(string[] args){Console.WriteLine("hello world&#xf…

TCP机制之确认应答及超时重传

TCP因为其可靠传输的特性被广泛使用,这篇博客将详细介绍一下TCP协议是如何保证它的可靠性的呢?这得主要依赖于其确认应答及超时重传机制,同时三次握手四次挥手也起到了少部分不作用,但是主要还是由确认应答和超时重传来决定的;注意:这里的可靠传输并不是说100%能把数据发送给接…

JVM学习(五)--方法区

概念&#xff1a; 方法区就是存和类相关的东西&#xff0c;成员方法&#xff0c;方法参数&#xff0c;成员变量&#xff0c;构造方法&#xff0c;类加载器等&#xff0c;逻辑上存在于堆中&#xff0c;但是不同的虚拟机对它的实现不同&#xff0c;oracle的hotsport vm在1.6的时…

事务(SQL)

事务概述 事务是一组操作的集合&#xff0c;他是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向西永提交或撤销操作请求。这组操作&#xff0c;要么全部执行成功&#xff0c;要么全部执行失败。 事务操作 查看/设置事务提交方式 -- 查看/设置事务…

9.1.tensorRT高级(4)封装系列-自动驾驶案例项目self-driving-道路分割分析

目录 前言1. 道路分割总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-自动驾驶案例项目self-driving-道路分…

Linux入门之多线程|线程|进程基本概念及库函数

目录 一、线程 1.线程的概 补充知识点&#xff1a;页表 2.线程的优点 3.线程的缺点 4.线程异常 5.线程用途 二、线程与进程的区别与联系 三、关于进程线程的问题 0.posix线程库 1.创建线程 2.线程终止 3.取消线程 4.线程等待&#xff08;等待线程结束&#xff09;…

02|李沐动手学深度学习v2(笔记)

基础优化算法 导航 基础优化算法梯度下降1.1 小批量随机梯度下降1.2 小结 线性回归实现1. 处理数据1.3 生成大小为batch_size的小批量 2. 处理模型3. 模型评估4. 训练过程 梯度下降 针对我们的模型没有显示解。&#xff08;生活中很少能有完全符合的线性模型&#xff0c;大多数…

用户中心笔记-leovany

1. 安装 官方地址&#xff1a;https://pro.ant.design/zh-CN/docs/getting-started 1.1 Mac系统 1.1.1 安装yarn 安装yarn brew install yarn查看版本 brew -v 1.1.2 安装node // 安装node brew install node // 关联 brew unlink node && brew link node // 查看版…

信息系统安全运维模型 课堂记录

声明 本文是学习 信息系统安全运维管理指南. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 范围 本标准描述了信息系统安全运维管理体系&#xff0c;给出了安全运维策略、安全运维组织、安全运维规程和安全运维支撑系统等方面相关活动的目的、要求和…

【项目 计网9】4.25 IO多路复用简介 4.26select API介绍 4.27 select代码编写

文章目录 4.25 IO多路复用&#xff08;I/O多路转接&#xff09;简介4.26select API介绍4.27 select代码编写客户端程序select程序select的缺点 4.25 IO多路复用&#xff08;I/O多路转接&#xff09;简介 输入输出&#xff1a;以内存为主体 读写&#xff1a;以程序为主体 程序要…

2023-09-03 LeetCode每日一题(消灭怪物的最大数量)

2023-09-03每日一题 一、题目编号 1921. 消灭怪物的最大数量二、题目链接 点击跳转到题目位置 三、题目描述 你正在玩一款电子游戏&#xff0c;在游戏中你需要保护城市免受怪物侵袭。给你一个 下标从 0 开始 且长度为 n 的整数数组 dist &#xff0c;其中 dist[i] 是第 i …

从一到无穷大 #12 Planet-Scale In-Memory Time Series Database, Is it really Monarch?

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言约束优势数据模型写路径查询路径Field Hints Index可靠性 其他总结 引言 Monarc…