当前位置: 首页 > news >正文

算法设计与分析第二章期末总结

一. 欧几里得算法(Euclidean Algorithm)

算法描述

欧几里得算法,又称辗转相除法,用于计算两个整数的最大公约数(GCD)。算法基于这样一个事实:两个整数的最大公约数与其中较小的数和两数的差的最大公约数相同。通过递归或迭代地应用这一性质,我们可以找到两个整数的最大公约数。

算法步骤

  1. 确定两个非负整数ab,其中a > b
  2. 使用a除以b得到余数r
  3. b赋值给a,将余数r赋值给b
  4. 重复步骤2和3,直到b为0。此时a即为所求的最大公约数。

代码模板

//模板一:
int gcd(int a, int b)
{while(b){int r = a % b;a = b;b = r;}return a;
}//模板二:
int gcd(int a, int b)
{return b ? gcd(b, a % b) : a;
}

拓展题目链接

⌈ AcWing 872. 最大公约数 ⌋



二. Fibonacci 数列

递归解法(不推荐使用)

int fibonacci(int n)
{//数列由 0 和 1 开始if(n <= 2) return 1;return fibonacci(n-1) + fibonacci(n-2);
}

递推解法

const int N = 100000000;int f3(int n)
{a[1] = a[2] = 1;for (int i = 3; i <= n; i ++ ){a[i] = a[i - 1] + a[i - 2];}return a[n];
}

递归+滚动变量

int fibonacci(int n)
{int a = 1, b = 1;int sum;for(int i = 3; i <= n; i++){sum = a+b;a = b;b = sum;}return b;
}

拓展题目链接

⌈821. 跳台阶Ⅰ - AcWing题库⌋

⌈5292. 跳台阶Ⅱ - AcWing题库⌋



三. 归并排序

归并排序(Merge Sort)是一种典型的分治(Divide and Conquer)算法,它将一个大问题分解成两个或更多个相同或相似的小问题,递归地解决这些小问题,然后将解决方案组合起来,以解决原始问题。
在这里插入图片描述

算法描述

归并排序的主要思想是将待排序的序列分割成若干个子序列,每个子序列是一个有序的序列。然后再把有序子序列合并为整体有序序列。

算法步骤

在这里插入图片描述

  1. 分解:将当前需要排序的数组按照中间索引分成两个子数组,直到子数组的大小为1。

  2. 递归进行排序:递归地对子数组进行排序。由于数组被分解成单个元素,所以它们被认为是有序的。递归进行,直到合并成1个完整的数组。

  3. 合并:将两个有序子数组合并成一个有序数组。这是归并排序算法的核心步骤。


合并步骤详解

  1. 有数组q, 左端点l, 右端点r

  2. 确定划分边界mid

  3. 递归处理子问题q[l..mid]q[mid+1..r]

  4. 合并子问题

    1. 主体合并:至少有一个小数组添加到tmp数组中;
    2. 收尾:可能存在的剩下的一个小数组的尾部直接添加到tmp数组中;
    3. 复制回来:tmp数组覆盖原数组;

代码模板

void merge_sort(int q[], int l, int r)
{//递归的终止情况if(l >= r) return ;//第一步:分成子问题int mid = r + l >> 1;//第二步:递归处理子问题merge_sort(q, l, mid);merge_sort(q, mid+1, r);//第三步:合并子问题int k = 0, i = l, j = mid+1;while(i <= mid && j <= r)if(q[i] <= q[j]) tmp[k++] = q[i++];else tmp[k++] = q[j++];while(i <= mid) tmp[k++] = q[i++];while(j <= r) tmp[k++] = q[j++];for(k = 0, i = l; i <= r; k++, i++) q[i] = tmp[k];
}

题目链接

⌈787. 归并排序 - AcWing题库⌋



四. 快速排序算法

在这里插入图片描述

算法描述

快速排序是一种采用分治策略的排序算法。它选择一个基准元素(pivot),通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比基准元素小,另一部分的所有数据都比基准元素大,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行。

算法步骤

  1. 选择基准:从待排序序列中选择一个元素作为基准(x)。基准的选择有多种方式,比如选择序列的第一个元素、最后一个元素、中间元素或随机选择。

  2. 分割操作

    • 初始化两个指针,一个指向序列的开始(l),一个指向序列的末尾(r)。
    • l < r时进行循环:
      • 如果l指向的元素小于或等于基准,则l自增。
      • 如果r指向的元素大于基准,则r自减。
      • 如果l指向的元素大于基准且r指向的元素小于基准,则交换这两个元素,并继续移动lr指针。
    • 以基准元素为界,将序列分割为两个子序列:基准左侧所有元素均比基准小,右侧的所有元素都比基准大。
  3. 递归排序

    • 对基准左侧的子序列进行快速排序。
    • 对基准右侧的子序列行快速排序。
  4. 合并结果:由于每次分割操作后基准元素都处于其最终排序后的正确位置,因此无需合并操作,递归调用结束后,整个序列就已经有序了。

代码模板

void quick_sort(int q[], int l, int r)
{//递归的终止情况if(l >= r) return ;//第一步:分成子问题int i = l - 1, j = r + 1;int x = q[l + r >> 1];while(i < j){do i++; while(q[i] < x);do j--; while(q[j] > x);if(i < j) swap(q[i], q[j]);}//第二步:递归处理子问题quick_sort(q, l, j), quick_sort(q, j+1, r);//第三步:子问题合并.快排这一步不需要操作,但归并排序的核心在这一步骤
}

题目链接

785. 快速排序 - AcWing题库



五. 整数二分查找算法

二分查找算法(Binary Search)是一种在有序数组中查找某一特定元素的搜索算法。

算法描述

二分查找算法通过不断将待查找的区间减半,从而快速定位到目标元素的位置。算法的基本思想是将数组的中间元素与目标值进行比较,如果中间元素正好是要查找的元素,则搜索过程结束;如果目标值大于或小于中间元素,则在数组大于或小于中间元素的那一半中继续查找,直到找到目标值或搜索区间为空。

算法步骤

在这里插入图片描述

  1. 初始化:设定数组的起始索引 left 为 0,终止索引 right 为数组长度减 1(即 len(arr) - 1)。

  2. 循环条件:当 left 小于等于 right 时,执行循环体内的步骤。

  3. 计算中间索引:计算当前搜索区间的中间索引 mid,可以通过 (left + right) / 2 来得到。

  4. 比较目标值与中间元素

    • 如果 arr[mid] 等于目标值 target,则找到了目标值,返回 mid
    • 如果 arr[mid] 小于目标值 target,说明目标值在 mid 的右侧,因此更新 leftmid + 1,继续在右半部分搜索。
    • 如果 arr[mid] 大于目标值 target,说明目标值在 mid 的左侧,因此更新 rightmid - 1,继续在左半部分搜索。
  5. 循环结束:如果循环结束都没有找到目标值,则返回 -1 或其他表示未找到的值。

代码模板

int bsearch(int l, int r)
{l = l-1, r = r+1;while(l + 1 != r){int mid = l + r >> 1;if(IsBlue(mid)) l = mid;else r = m;}return l or r;
}

函数IsBlue(mid)的确定:
在这里插入图片描述

注意事项

  • 二分查找要求数组必须是有序的
  • 二分查找的时间复杂度为O(log n),其中n是数组的长度。

题目链接

789. 数的范围 - AcWing题库



六. 快速幂

快速幂算法(Binary Exponentiation)是一种用于计算幂的高效算法。它的核心思想是将指数表示为二进制形式,并利用二进制数的每一位来快速计算幂。

算法描述

快速幂算法通过不断将指数减半和取底数的平方来减少计算幂所需的乘法次数。具体来说,它将指数转换为二进制形式,然后对于二进制形式中的每一位,如果它是1,则将当前累积的结果乘以底数;如果它是0,则不做任何操作。同时,每次迭代都将底数平方,并将指数右移一位。

算法步骤

在这里插入图片描述

  1. 初始化:设置res为1(因为任何数的0次幂都是1),base为给定的底数,exponent为给定的指数。

  2. 当指数不为0时

    • 如果exponent的二进制表示的最低位是1(即exponent是奇数),则将result乘以base
    • base平方(即base = base * base)。
    • exponent右移一位(即exponent = exponent >> 1),这相当于将exponent除以2。
  3. 返回结果:返回result作为最终的计算结果。

代码模板

//求 m^k,时间复杂度 O(logn)int qmi(int m, int k)
{int res = 1, t = m;while (k){if (k&1) res = res * t;t = t * t;k >>= 1;}return res;
}

带取模的代码模板(用于大数计算)

在实际应用中,当处理大数时,为了防止溢出,通常会在每次乘法后进行取模操作。这可以通过在每一步的乘法后添加一个% mod操作来实现。

//求 m^k mod p,时间复杂度 O(logk)int qmi(int m, int k, int p)
{int res = 1 % p, t = m;while (k){if (k&1) res = res * t % p;t = t * t % p;k >>= 1;}return res;
}
typedef long long LL;LL pmi(int a, int k, int p)
{LL res = 1 % p, t = a;while(k){if(k&1) res = res * t % p;t = t * t % p;k >>= 1;}return res;
}

这样,即使底数和指数都非常大,也可以通过快速幂算法在合理的时间内计算出结果的模值。

题目链接 & 视频链接

⌈875. 快速幂 - AcWing题库⌋

⌈快速幂都能做什么?小小的算法也有大大的梦想_哔哩哔哩_bilibili⌋

相关文章:

  • Security OAuth2 SSO单点登录源码剖析ing...(二)
  • 从程序被SQL注入来MyBatis 再谈 #{} 与 ${} 的区别
  • Python pdf2imges -- pdf文件转图片
  • QT:信号与槽
  • WordPress安装memcached提升网站速度
  • Value-Based Reinforcement Learning(2)
  • 2024.5.26.python.exercise
  • pod 之资源限制 与健康检查
  • Vue项目中npm run build 卡住不执行的几种情况(实战版)
  • P2118 [NOIP2014 普及组] 比例简化
  • Spring从零开始学使用系列(四)之@PostConstruct和@PreDestroy注解的使用
  • 化学中的不确定性。
  • 人工智能+量子计算:飞跃现实边界还是科技幻想?
  • java网络:过滤器修改请求头
  • 一、Elasticsearch介绍与部署
  • 「译」Node.js Streams 基础
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
  • ES6语法详解(一)
  • java8 Stream Pipelines 浅析
  • JavaScript设计模式与开发实践系列之策略模式
  • LeetCode算法系列_0891_子序列宽度之和
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • MySQL几个简单SQL的优化
  • Redux系列x:源码分析
  • tab.js分享及浏览器兼容性问题汇总
  • VUE es6技巧写法(持续更新中~~~)
  • 大数据与云计算学习:数据分析(二)
  • 聊聊flink的TableFactory
  • 前端相关框架总和
  • 收藏好这篇,别再只说“数据劫持”了
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 微信小程序:实现悬浮返回和分享按钮
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 正则表达式
  • 《码出高效》学习笔记与书中错误记录
  • 【干货分享】dos命令大全
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (zhuan) 一些RL的文献(及笔记)
  • (八)Flask之app.route装饰器函数的参数
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (六)激光线扫描-三维重建
  • (区间dp) (经典例题) 石子合并
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (微服务实战)预付卡平台支付交易系统卡充值业务流程设计
  • (转)Scala的“=”符号简介
  • (转)菜鸟学数据库(三)——存储过程
  • (自用)交互协议设计——protobuf序列化
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .gitignore文件_Git:.gitignore
  • .net 程序发生了一个不可捕获的异常
  • .Net 访问电子邮箱-LumiSoft.Net,好用