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

算法入门数学基础

目录

 例题1:辗转相除法(欧几里得算法)

例题2:n的n次方求个位

例题3:斐波那契规律题

例题4:快速幂

快速幂的模版:

例题5:二分查找

二分查找模版:

例题6: 二分的应用

例题7:三分查找


本章重点:

  • 欧几里得算法
  • 找规律
  • 快速幂运算
  • 二分查找
  • 三分查找

导引问题:整数求和

任务:给定一个正整数n,计算1+2+3+....+n的结果,其中n  <= 50000。

代码1:使用循环累加

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {int n = 0;int sum = 0;scanf("%d", &n);int i = 0;for (i = 0; i <= n; i++) {sum += i;}printf("%d\n", sum);return 0;
}

方法2:使用高斯公式:n +(n+ 1) / 2

        那么问题来了,我们知道题目的范围n  <= 50000。如果这里我们假设n = 50000。如果使用高斯公式50000 * 50001 = 2,500,050,000超过了int类型。这里就需要使用long long。那么可以不使用long long 来计算吗?

        解决方案1:使用long long。%lld 8字节64bit。

        解决方案2:先除后乘 这里要考虑奇偶性,做一个判断。     

 例题1:辗转相除法(欧几里得算法

任务:给定两个正整数,计算这两个数的最小公倍数(能同时被两个数整除的最小数)。

样例输入:

10 14 

4 6

样例输出:

70 

12

方法1:暴力枚举

方法2:从大数开始枚举大数的倍数(枚举的改进)。

方法3:辗转相除法。

公式:LCM(A,B) = A * B / GCD(A, B)

上面公式解释A 和 B 的最小公倍数 = A * B / (A和B的最大公约数)。

注意:上面公式可以会出现导引中提到过的一个问题 int 类型可能会爆。所以也要进行转换先除后乘, 或者使用long long类型。

这里以10 和 14 作为例子进行说明求解过程:具体过程看上图。

#include<stdio.h>//辗转相除法求gcd
int gcd(int da, int xiao) {int tep;while (xiao != 0) {tep = da % xiao;da = xiao;xiao = tep;}return da;
}int main() {//求a和b的最小公倍数int a = 14;int b = 10;int ans = a / gcd(a, b)*b;printf("%d \n", ans);return 0;
}

思考:大小两个参数位置是否可以变?答案可以,循环一次就能纠正过来,多做一次循环。

例题2:n的n次方求个位

任务:给定一个整数N,请计算N个N相乘的结果的个位数是都少(1 <= N <= 1000)。

方法1:暴力。这显然是不行的原因N的N次方太大了long long类型都不能放下。

方法2:做n - 1趟循环每次都取出个位数。为什么只取出个位就可以?原因:因为结果要的是个位所以其他位的不会影响个位的结果。

#include<stdio.h>int main() {int N = 0;scanf("%d", &N);int i = 0;int ans = N;for (i = 0; i < N - 1; i++) {ans =  N * ans;ans = ans % 10;}printf("%d", ans);return 0;
}

方法3:抽屉原理,找规律。因为个位数只能有10种情况。在很多题目中会出现循环节

        抽屉原理:桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面放不少于两个苹果。这一现象就是我们所说的“抽屉原理”。 抽屉原理的一般含义为:“如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有n+1个元素放到n个集合中去,其中必定有一个集合里至少有两个元素。” 抽屉原理有时也被称为鸽巢原理。它是组合数学中一个重要的原理。

例题3:斐波那契规律题

        有一种fibonacci数列,定义如下:F(0) = 7,F(1) = 11, F(n) = F(n - 1) + F(n - 2)  (n >= 2)。给定一个n(n <= 1 000 000),请判断F(n)能否被3整除,分别输出yes和no。

分析这里的n太大了暴力绝对不可行。那么怎么去考虑呢?

改良暴力:通过上面的地推式推出:F(n) % 3 = (F(n - 1) % 3 + F(n - 2)  % 3) % 3

打表找规律:

#include<stdio.h>int main() {//int arr[100];//arr[0] = 7 % 3;//arr[1] = 11 % 3;//int i = 0;////for (i = 2; i < 100; i++) {//	int ant = (arr[i - 1] % 3 + arr[i - 2] % 3) % 3;//	arr[i] = ant;//}//for (i = 0; i < 100; i++) {//	printf("%d ", arr[i]);//}//通过打表没8个为一个循环节//1 2 0 2 2 1 0 1 //3 7int N;scanf("%d", &N);if ((N % 8) == 3 || (N % 8) == 7) {printf("%s\n", "yes");}else {printf("no");}return 0;
}

例题4:快速幂

任务:求A^B的最后三位数表示的整数(1 <= A, B <= 10000)。

样例输入:

2 3

12 6

样例输出:

8

984

方法1:直接暴力; 出现的问题数据太大可能会使int 或者long long爆掉。

方法2:改进的暴力。这里的A, B都小于10000可以使用暴力。如果数据更大该怎么办,看方法3。

#include<stdio.h>int main() {int A;int B;scanf("%d %d", &A, &B);int ans = 1;int i = 0;for (i = 0; i < B; i++) {ans *= A;ans %= 1000;  //题目只要最后三位数}printf("%d\n", ans);return 0;
}

方法3:快速幂

        顾名思义,快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。

        快速幂算法的核心思想就是每一步都把指数分成两半,而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变。        

快速幂的模版:

// 快速幂模版递归方式
int power(int a, int n) {int ans;if (n == 0) {ans = 1;}else {ans = power(a * a, n / 2);if (n % 2 == 1) {ans *= a;}}return ans;
}//快速幂非递归方法
int power(int a, int n) {int ans = 1;while (n) {if (n % 2==1) {ans = ans * a;}a = a * a;n /= 2;}return ans;
}

快速幂模版取模版本:

        取模的原因:是因为A^N次方一般特别大在算法题出现类似的题一般会取模。下面代码是对1000取模。

// 快速幂模版递归方式
int power(int a, int n) {int ans;if (n == 0) {ans = 1;}else {ans = power((a * a) % 1000, n / 2);if (n % 2 == 1) {ans =(ans * a % 1000);}}return ans;
}//快速幂非递归方法
int power(int a, int n) {int ans = 1;while (n) {if (n % 2==1) {ans = (ans * a) % 1000;}a = (a * a) % 1000;n /= 2;}return ans;
}

例题5:二分查找

        给出若干个(可以很多)有序的整数,请查找某个元素是否存在,比如在1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20中查找15。如果找到返回元素的下标,找不到返回-1。

注意:二分查找的前提是——数据是有序的。

        二分法搜索(Binary Search),又称折半搜索、对数搜索,是一种在有序数组中查找特定元素的搜索算法 。该算法时间复杂度为O(log n),迭代实现空间复杂度为O(1),递归实现则为O(log n)。

二分查找模版:

非递归模版

//二分查找模版
int BiSearch(int a[], int n, int x) {/*arr数组 * n是数组的长度* x所要查找的数值*/int left = 0;int right = n - 1;while (left <= right) {				//注意:这里等号不能少int mid = (left + right) / 2;   //整数除法if (a[mid] == x) {				//找到的情况return mid;}if (x > a[mid]) {				//如果比查找的值大left = mid + 1;}else {right = mid - 1;			//如果比查找的值小}}return -1;  //没有找到返回-1
}

递归模版:

  写递归时候一般先写递归出口

//二分查找模版
int BiSearch(int a[], int x, int left, int right) {/*a数组 * x所要查找的数值*/if (left > right) {//递归出口return -1;}else {int mid = (left + right) / 2;if (a[mid] == x)return mid;else if (x > a[mid])return BiSearch(a, x, mid + 1, right);elsereturn BiSearch(a, x, left, mid - 1);}
}

思考:在一百万个有序元素中用二分查找一个元素大约需要比较多少次?

答案:大约20次。

时间复杂度:O(logN)。

例题6: 二分的应用

        给出方程:其中,实数Y满足(fabs(Y)<= 1e10)请输出x的区间[0, 100]的解,精确到小数点后4位。(输入Y求x)

#include<stdio.h>
double f(double x){//题目中的式子return 8 * x*x*x*x + 7 * x*x*x + 2 * x*x + 3 * x + 6;
}
int main() {double Y;double left, right, mid;int t;scanf("%d", &t);//测试次数while (t--) {scanf("%lf", &Y);if (f(0) <= Y && Y <= f(100)) {left = 0;right = 100;while (right - left > 1e-6) {mid = (left + right) / 2;double ans = f(mid);if (ans > Y)right = mid - 1e-7;elseleft = mid + 1e-7;}printf("%.4f\n", (left + right) / 2);}elseprintf("No solution!\n");//没找到符合的结果}return 0;
}

例题7:三分查找

        给定函数:其中,实数y满足(0 < y < 1e10)请输入x在区间[0, 100]时函数F(x)的最小值,结果精确到小数点后4位。(输入y求x)

方法1:求导找到倒数为0的点就是最小值

方法2:三分查找

        三分查找(Ternary Search)是一种用于在单峰函数(凸函数或凹函数)上高效逼近最大值或最小值的搜索算法,通过每次迭代将搜索区间三等分并排除无效部分,时间复杂度为O(log₃n)

         三分查找:用来求极值点,和二分查找不同,二分查找比较的是所查找的值是否等于下标为mid元素的值,而三分查找比较的是LeftThird 和 RigthThird的Y值。

        总结:二分查找要求单调性。

                    三分的前提------数据的凸凹性,这里的凸凹不要求单调。

非递归

#include <stdio.h>
#include <math.h>
double pow(double a, int n) {double ans = 1;for (int i = 0; i < n; i++) {ans *= a;}return ans;
}double f(double x, double y) {return 6 * pow(x, 7) + 8 * pow(x, 6) +7 * pow(x, 3) + 5 * pow(x, 2) - y * x;
}
int main() {double y;scanf("%lf", &y);double left = 0;double right = 100;//这里的循环结束标志是两个数的f函数的绝对值小于1e-7,因为要求保留4位小数double epsilon = 1e-7;while (fabs(right - left) > epsilon) {double leftThird = left + (right - left) / 3;double rightThird = right - (right - left) / 3;if (f(leftThird, y) < f(rightThird, y)) {right = rightThird - epsilon;
//这里是不需要考虑偏移的,原因是因为循环结束条件是绝对值小于1e-7,如果left == right也不会死循环}else {left = leftThird + epsilon;}}printf("%.4lf", f((left + right) / 2, y));return 0;
}

递归

#include <stdio.h>
#include <math.h>double pow(double a, int n) {double ans = 1;for (int i = 0; i < n; i++) {ans *= a;}return ans;
}double f(double x, double y) {return 6 * pow(x, 7) + 8 * pow(x, 6) +7 * pow(x, 3) + 5 * pow(x, 2) - y * x;
}double san(double y, double left, double right) {double epsilon = 1e-7;if (fabs(right - left) < epsilon) {return f((left + right) / 2, y);}double leftThird = left + (right - left) / 3;double rightThird = right - (right - left) / 3;if (f(leftThird, y) < f(rightThird, y)) {return san(y, left, rightThird - epsilon);}else {return san(y, leftThird + epsilon, right);}
}int main() {double y;scanf("%lf", &y);double left = 0;double right = 100;double ans = san(y, left, right);printf("%.4lf", ans);return 0;
}

http://www.dtcms.com/a/490493.html

相关文章:

  • 错误边界:用componentDidCatch筑起React崩溃防火墙
  • 网站备案提交管局原创软文
  • 成都比较好的网站建设公司视频制作和剪辑软件
  • 如何从电脑上卸载安卓应用程序
  • 每日手撕算法--哈希映射/链表存储数求和
  • k8s的pvc和pv
  • RK3562核心板/开发板RT-Linux系统实时性及硬件中断延迟测试
  • node.js把webp,gif格式图片转换成jpg格式图片
  • 不能识别adb/usb口记录
  • SpringBoot-常用注解
  • 支付商城网站制作软件开发报价表
  • wordpress类似的平台快速优化排名公司推荐
  • Git 基础操作指南
  • 网站给部分文字做遮挡代码wordpress主题仿逛丢
  • 【bug】大模型微调bug:OSError: Failed to load tokenizer.| Lora
  • 视频生成的背后机理:Wan2技术报告分析
  • 有什么做衣服的网站吗天津市建筑信息平台
  • HTB BoardLight writeup(enlightenment 0.23.1 exploit)
  • 唐山网站搭建平台制作计划
  • 智能体面试题:ReAct框架 是什么
  • 泰山派rk3566 wifi基础知识
  • 【无标题】大模型-AIGC技术在文本生成与音频生成领域的应用
  • 渗透测试(2):不安全配置、敏感明文传输、未授权访问
  • 有记事本做简易网站深圳网站设计x程序
  • AI教育开启新篇章
  • 使用bert-base-chinese中文预训练模型,使用 lansinuote/ChnSentiCorp 中文网购评价数据集进行情感分类微调和训练。
  • 国内做设计的网站做视频素材哪个网站好
  • WebGIS包括哪些技术栈?
  • Python全栈(基础篇)——Day13:后端内容(模块详解)
  • 科创企业品牌营销:突破与发展之路