基础算法 - 快速排序、归并排序、二分查找、高精度模板、离散化数据

文章目录

  • 前言
  • Part 1:排序
    • 一、快速排序
    • 二、归并排序
  • Part 2:二分
    • 一、二分 - 查找左边界
    • 二、二分 - 查找右边界
  • Part 3:高精度
    • 一、高精度加法
    • 二、高精度减法
    • 三、高精度乘法
    • 四、高精度除法
  • Part 4:离散化
    • 一、区间和

前言

由于本篇博客相较而言都是算法中最基础的模板,包括快速排序、归并排序、二分、高精度加减乘除法、离散化。这些基础模板多与其他算法混合考察,这些模板是许多算法的实现基础。

Part 1:排序

快速排序和归并排序都属于分治思想,分治分为三步:

1.分成子问题
2.递归处理子问题
3.子问题合并

一、快速排序

  • 核心思想是:是将问题划分为子问题的过程中不断解决。不断根据一个分割点,交换前后数据,使得前一部分小于分割点,后一部分大于分割点,分割点在两部分中间,再根据分割位置将其分为两部分重新进行此操作,直到无法再分
void quick_sort(int q[], int l, int r)
{//递归的终止情况if(l >= r) return;//第一步:分成子问题int i = l - 1, j = r + 1, 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);//第三步:子问题合并.快排这一步不需要操作,但归并排序的核心在这一步骤
}

二、归并排序

  • 核心思想:不断将问题划分为子问题,再从子问题开始操作,累加出问题的答案。将数组不断划分为两部分,在无法划分时,将每个分治最后一次划分的两部分合并排序,重复从小问题向原问题操作,合并为排序答案
void merge_sort(int q[], int l, int r)
{//递归的终止情况if(l >= r) return;//第一步:分成子问题int mid = l + r >> 1;//第二步:递归处理子问题merge_sort(q, l, mid ), merge_sort(q, mid + 1, r);//第三步:合并子问题int k = 0, i = l, j = mid + 1, tmp[r - l + 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];
}

Part 2:二分

一般二分应用于无非下面这四种情况:
1:找大于等于数的第一个位置 (满足某个条件的第一个数)- 左边界
2:找小于等于数的最后一个数 (满足某个条件的最后一个数)- 右边界
3.查找最大值 (满足该边界的右边界)- 右边界
4.查找最小值 (满足该边界的左边界) - 左边界

一、二分 - 查找左边界

//查找左边界 SearchLeft 简写SL
int SL(int l, int r)
{while (l < r){int mid = l + r >> 1;if (check(mid)) r = mid; else l = mid + 1; }   return l;
}

二、二分 - 查找右边界

//查找右边界 SearchRight 简写SR 
int SR(int l, int r) 
{while (l < r){                   int mid = l + r + 1 >> 1; //需要+1 防止死循环if (check(mid)) l = mid;else r = mid - 1; }return r; 
}

总结以下记忆方式:有加必有减!!!

int mid = l + r + 1 >> 1; //+1为加
if (check(mid)) l = mid;
else r = mid - 1; //-1为减

Part 3:高精度

一、高精度加法

#include <iostream>
#include <vector>using namespace std;vector<int> add(vector<int> &A, vector<int> &B)
{//为了方便计算,让A中保存较长的数字, B中保存较短的数字if (A.size() < B.size()) return add(B, A);//保存结果的数组vector<int> C;//进位,开始时是0int t = 0;//依次计算每一位for (int i = 0; i < A.size(); i ++ ){t += A[i];//加上 A 的第 i 位上的数字if (i < B.size()) t += B[i];//加上 B 的第 i 位上的数字C.push_back(t % 10); //C 中放入结果t /= 10;//t 更新成进位}//最后如果进位上有数,放进结果数组if (t) C.push_back(t);return C;//返回结果
}int main()
{string a, b;//以字符串形式保存输入的两个整数vector<int> A, B;//保存两个整数的数组cin >> a >> b;//接收输入for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');//倒序存储第一个数for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');//倒序存储第二个数auto C = add(A, B);//调用加和函数for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];//倒序输出C中的数字cout << endl;return 0;
}

二、高精度减法

#include <iostream>
#include <vector>using namespace std;bool cmp(vector<int>& A, vector<int> &B)
{if(A.size() != B.size()) return A.size() > B.size();  //直接ruturn 了就不用elsefor(int i = A.size(); i >= 0; i--)if(A[i] != B[i])return A[i] > B[i];return true;
}vector <int> sub(vector<int>& A, vector<int> &B)
{vector<int> C;int t = 0;for(int i = 0; i < A.size(); i++){t = A[i] - t;if(i < B.size()) t -= B[i];C.push_back((t + 10) % 10 ); // 合而为1if(t < 0)  t = 1;else t = 0;}while(C.size() > 1 && C.back() == 0) C.pop_back();  //去掉前导0return C;
}int main()
{string a ,b;vector<int> A, B;cin >> a >> b ;for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');for(int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');if (cmp(A,B)) {auto C = sub(A, B);for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);return 0;}else{auto C = sub(B, A);printf("-");for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);return 0;}
}

三、高精度乘法

高精度 X 低精度

#include <iostream>
#include <vector>using namespace std;vector <int> mul(vector <int> & A, int b) 
{vector <int> C;int t = 0;for (int i = 0; i < A.size(); i ++) {t += A[i] * b;       // t + A[i] * b = 7218C.push_back(t % 10); // 只取个位 8t /= 10;             // 721 看作 进位}// 处理最后剩余的 twhile (t) {            C.push_back(t % 10);t /= 10;}while (C.size() > 1 && C.back() == 0) C.pop_back();return C;
}int main() {string a;int b;cin >> a >> b;vector <int> A;for (int i = a.size() - 1; i >= 0; i --) A.push_back(a[i] - '0');auto C = mul(A, b);for (int i = C.size() - 1; i >= 0; i --) {cout << C[i];}return 0;
}

高精度 X 高精度

#include <iostream>
#include <vector>using namespace std;vector<int> mul(vector<int> &A, vector<int> &B) 
{vector<int> C(A.size() + B.size() + 7, 0); // 初始化为 0,C的size可以大一点for (int i = 0; i < A.size(); i++)for (int j = 0; j < B.size(); j++)C[i + j] += A[i] * B[j];int t = 0;for (int i = 0; i < C.size(); i++) // i = C.size() - 1时 t 一定小于 10{t += C[i];C[i] = t % 10;t /= 10;}while (C.size() > 1 && C.back() == 0) C.pop_back(); // 必须要去前导 0,因为最高位很可能是 0return C;
}int main() 
{string a, b;cin >> a >> b; // a = "1222323", b = "2323423423"vector<int> A, B;for (int i = a.size() - 1; i >= 0; i--)A.push_back(a[i] - '0');for (int i = b.size() - 1; i >= 0; i--)B.push_back(b[i] - '0');auto C = mul(A, B);for (int i = C.size() - 1; i >= 0; i--)cout << C[i];return 0;
}

大数相加A+B和大数相乘A*B通用模板

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;vector<int> add(vector<int> A, vector<int> B) 
{// A: 4 3 2 1// B: 6 5vector<int> C(max(A.size(), B.size()) + 7, 0);  // 数组C开大一点没事,反正可以去前导零的for (int i = 0; i < A.size(); i ++) C[i] += A[i];for (int i = 0; i < B.size(); i ++) C[i] += B[i];// 处理进位for (int i = 0; i + 1 < C.size(); i ++) {C[i + 1] += C[i] / 10;C[i] %= 10;}// 处理前导零while (C.size() > 1 && C.back() == 0) C.pop_back();reverse(C.begin(), C.end());return C;
}vector<int> mul(vector<int> A, vector<int> B) 
{// A: 4 3 2 1// B: 6 5vector<int> C(A.size() + B.size() + 7, 0);  // 数组C开大一点没事,反正可以去前导零的for (int i = 0; i < A.size(); i ++) {for (int j = 0; j < B.size(); j ++) {C[i + j] += A[i] * B[j];}}// 处理进位for (int i = 0; i + 1 < C.size(); i ++) {C[i + 1] += C[i] / 10;C[i] %= 10;}// 处理前导零 "0000" 去掉前导零while (C.size() > 1 && C.back() == 0) C.pop_back();reverse(C.begin(), C.end());return C;
}int main() 
{string s1 = "9899", s2 = "100";vector<int> A, B;for (int i = s1.size() - 1; i >= 0; i --) A.push_back(s1[i] - '0');for (int i = s2.size() - 1; i >= 0; i --) B.push_back(s2[i] - '0');vector<int> C = add(A, B);cout << s1 << "+" << s2 << "=";for (int i = 0; i < C.size(); i ++) cout << C[i];cout << endl;C = mul(A, B);cout << s1 << "*" << s2 << "=";for (int i = 0; i < C.size(); i ++) cout << C[i];cout << endl;return 0;
}

四、高精度除法

#include<iostream>
#include<vector>
#include<algorithm>using namespace std;//int r=0;
vector<int> div(vector<int> &A,int B,int &r)//r传入r的地址,便于直接对余数r进行修改
{vector<int> C;//对A从最高位开始处理for(int i=0;i<A.size();i++){r=r*10+A[i];//将上次的余数*10在加上当前位的数字,便是该位需要除的被除数C.push_back(r/B);//所得即为商在这一位的数字r=r%B;}//由于在除法运算中,高位到低位运算,因此C的前导零都在vector的前面而不是尾部,vector只有删除最后一个数字pop_back是常数复杂度,而对于删除第一位没有相应的库函数可以使用,而且删除第一位,其余位也要前移,//因此我们将C翻转,这样0就位于数组尾部,可以使用pop函数删除前导0reverse(C.begin(),C.end());while(C.size()>1&&C.back()==0) C.pop_back();return C;
}int main()
{string a;int B,r=0; //代表余数cin>>a>>B;vector<int> A;for(int i=0;i<a.size();i++) A.push_back(a[i]-'0');//注意这次的A是由高为传输至低位,由于在除法的手算过程中,发现从高位进行处理//for(int i=0;i<A.size();i++) cout<<A[i];//cout<<B;auto C = div(A,B,r);for(int i=C.size()-1;i>=0;i--) cout<<C[i];//将C从最高位传给最低位cout<<endl<<r;//输出余数cout<<endl;return 0;
}

Part 4:离散化

一、区间和

题目描述:假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。

输入:第一行包含两个整数 n 和 m。接下来 n 行,每行包含两个整数 x 和 c。再接下来 m 行,每行包含两个整数 l 和 r。
输出:共 m 行,每行输出一个询问中所求的区间内数字和。

  • 离散化的本质,是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量
  • 该题解决办法就是开辟额外的数组存放原来的数组下标,或者说下标标志,本文是原来上的数轴上的非连续点的横坐标。此处的做法是是对原来的数轴下标进行排序,再去重,根据二分得到该数在开辟的连续数组中的位置
#include <iostream>
#include <vector>
#include <algorithm>using namespace std;const int N = 300010; //n次插入和m次查询相关数据量的上界int n, m;
int a[N];//存储坐标插入的值
int s[N];//存储数组a的前缀和
vector<int> alls;  //存储(所有与插入和查询有关的)坐标
vector<pair<int, int>> add, query; //存储插入和询问操作的数据//返回的是输入的坐标的离散化下标
int find(int x) 
{ int l = 0, r = alls.size() - 1;while (l < r) {int mid = l + r >> 1;if (alls[mid] >= x) r = mid;else l = mid + 1;}return r + 1;
}int main() 
{scanf("%d%d", &n, &m);for (int i = 1; i <= n; i++) {int x, c;scanf("%d%d", &x, &c);add.push_back({x, c});alls.push_back(x);}for (int i = 1; i <= m; i++) {int l , r;scanf("%d%d", &l, &r);query.push_back({l, r});alls.push_back(l);alls.push_back(r);}//排序,去重sort(alls.begin(), alls.end());alls.erase(unique(alls.begin(), alls.end()), alls.end());//执行前n次插入操作for (auto item : add) {int x = find(item.first);a[x] += item.second;}//前缀和for (int i = 1; i <= alls.size(); i++) s[i] = s[i-1] + a[i];//处理后m次询问操作for (auto item : query) {int l = find(item.first);int r = find(item.second);printf("%d\n", s[r] - s[l-1]);}return 0;
}

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

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

相关文章

“找不到msvcr90.dll无法启动软件如何解决

msvcr90.dll 是一个属于 Microsoft Visual C 2008 Redistributable Package 的动态链接库&#xff08;DLL&#xff09;文件。在Windows操作系统中&#xff0c;许多应用程序特别是那些使用Visual Studio 2008编译器开发的程序&#xff0c;在运行时可能需要调用这个库中的函数和资…

lua调用C++函数

第一步搭建lua的环境. win10 lua环境搭建-CSDN博客 我使用的环境是win10vs2015lua54 先来个最简单的lua调用C函数, 无参数无返回值的 第一步:定义C函数. int CTest(lua_State* L) // 返回值是固定的int类型,返回0表示没有返回参数,返回1表示有一个返回参数 {std::cout &l…

K8S高级篇:138页经典实战案例,图文并茂代码齐全,仅限3天分享

相信很多朋友都听过云原生和容器技术&#xff0c;当然也少不了K8S的大名&#xff0c;在“容器技术革命”中&#xff0c;K8S俨然已经成为容器技术的事实标准&#xff0c;各个知名互联网企业前仆后继地拥抱云原生&#xff0c;争先恐后地把容器和K8S作为战略重心之一。 容器技术发…

HTTP头部信息解释分析(详细整理)

这篇文章为大家介绍了HTTP头部信息&#xff0c;中英文对比分析&#xff0c;还是比较全面的&#xff0c;若大家在使用过程中遇到不了解的&#xff0c;可以适当参考下 HTTP 头部解释 1. Accept&#xff1a;告诉WEB服务器自己接受什么介质类型&#xff0c;*/* 表示任何类型&#…

WordPress上传图片错误:不是合法的JSON响应

最近在进行WordPress迁移至新服务器的过程中&#xff0c;遭遇到一个棘手的问题&#xff0c;即在编辑文章并上传图片时&#xff0c;不断遭遇“此响应不是合法的JSON响应”的错误。经过多次验证和搜索&#xff0c;最终确定问题的根本原因并不在于禁用 Gutenberg 编辑器或安装经典…

CSS变量和@property

CSS变量 var() CSS 变量是由CSS作者定义的实体&#xff0c;其中包含要在整个文档中重复使用的特定值。使用自定义属性来设置变量名&#xff0c;并使用特定的 var() 来访问。&#xff08;比如 color: var(--main-color);&#xff09;。 基本用法 CSS变量定义的作用域只在定义该…

【Kotlin】函数

1 常规函数 1.1 无参函数 fun main() {myFun() }fun myFun() {println("myFun") // 打印: myFun } 1.2 有参函数 1&#xff09;常规调用 fun main() {myFun("myFun") // 打印: myFun }fun myFun(str: String) {println(str) } 2&#xff09;形参指定默…

根据条件查询下载Excel表单(Java+Vue 及 Vue 两种方式)

目录 前言1. 基本知识2. 纯前端导入导出&#xff08;Vue&#xff09;3. 前后端&#xff08;Vue Java&#xff09; 前言 如果想要下载好看的Excel推荐阅读&#xff1a; 详细讲解Java使用EasyExcel函数来操作Excel表&#xff08;附实战&#xff09;详细讲解Java使用HSSFWorkbo…

23.基于springboot + vue实现的前后端分离-在线旅游网站系统(项目 + 论文PPT)

项目介绍 本旅游网站系统采用的数据库是MYSQL &#xff0c;使用 JSP 技术开发&#xff0c;在设计过程中&#xff0c;充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。 技术选型 后端: SpringBoot Mybatis 数据库 : MyS…

RK android11 user打开adb调试功能

目录build/make/core diff --git a/core/main.mk b/core/main.mk --- a/core/main.mk b/core/main.mk -280,7 280,7 ifneq (,$(user_variant)) ADDITIONAL_DEFAULT_PROPERTIES security.perf_harden1 ifeq ($(user_variant),user) - ADDITIONAL_DEFAULT_PROPER…

机器学习:原理、应用与未来展望

第一章 是什么 机器学习&#xff08;Machine Learning&#xff09;是一门跨学科的学科&#xff0c;它使用计算机模拟或实现人类学习行为&#xff0c;通过不断地获取新的知识和技能&#xff0c;重新组织已有的知识结构&#xff0c;从而提高自身的性能。机器学习涉及多个学科&am…

wordpress 开源主题

海外就医wordpress主题 出国看病、海外就医是越来越多中产家庭的选择&#xff0c;此wordpress主题适合做相关业务的公司官网。 https://www.jianzhanpress.com/?p5220 防护wordpress外贸主题 个人防护器具wordpress外贸主题&#xff0c;适合做劳动保护的外贸公司使用。 ht…

微信小程序中使用特使字体

1、首先下载字体文件 推荐几个常用下载字体的网站 https://font.chinaz.com/zhongwenziti.html https://www.hellofont.cn/ 2、转换字体 使用下面这个网站进行字体转换 https://transfonter.org/ 点击add fonts 按钮进行上传刚刚下载的字体文件选择formats格式&#xff1a;可…

关于CSS 优先级布局应用的教程

在前端开发中&#xff0c;CSS 的优先级布局是非常重要的一部分。通过合理地应用 CSS 优先级&#xff0c;我们可以更加灵活地控制页面的布局和样式。本教程将向您介绍如何利用 CSS 优先级进行布局&#xff0c;并通过实例展示其应用。 1. 了解 CSS 优先级 在 CSS 样式表中&…

【生活】程序人生之日常生活篇(附塑料分类标志 常用日常好物)

程序员生活指南之 【生活】程序人生之日常生活篇&#xff08;附塑料分类标志 & 常用日常好物&#xff09; 文章目录 1、关于本文2、居家相关2.1 蟑螂大战2.2 房间收纳&#xff08;寝室&#xff0c;租房&#xff0c;家里&#xff09;2.3 智能家居2.4 台灯选购2.5 塑料分类标…

深圳mes系统在智能制造中的重要意义

深圳mes系统在生产中具有重要意义&#xff0c;主要体现在以下几个方面&#xff1a; 生产计划可视化和优化&#xff1a;MES系统通过大量收集和分析工厂内部的实时数据&#xff0c;将数据可视化展示给运营和管理层&#xff0c;使企业决策者能够更加有效地进行生产计划的制定和…

高级优化理论与方法(二)

高级优化理论与方法&#xff08;二&#xff09; 上节回顾ConstrainedUnconstrainedFONCSONCexample 这节课的内容SOSC定理叙述证明例子 One-dimensional Search MethodsIterative MethodGolden Section SearchMethodIssues方法推理算法描述TimeExample Fibonacci MethodBisecti…

教师观包括哪些内容是什么

站在讲台上的老师&#xff0c;除了教你知识&#xff0c;还有哪些不为人知的角色和面孔&#xff1f;让我们一起揭开教师观的神秘面纱&#xff0c;看看老师们的“千面人生”。 现代教师已不再是单纯的知识传递者&#xff0c;他们更像是学习旅程中的导游和指南针。他们引导学生发现…

嵌入式Qt 对话框及其类型 QDialog

一.对话框的概念 对话框是与用户进行简短交互的顶层窗口。 QDialog是Qt中所有对话框窗口的基类。 QDialog继承与QWidfet是一种容器类型的组件。 QDialog的意义&#xff1a; QDialog作为一种专业的交互窗口而存在。 QDialog不能作为子部部件嵌入其他容器中。 QDialog是定制…

反函数的理解|反函数到底“反”的是什么?什么是反函数?

理解 将 yex 函数图像连同整个坐标系绕着 yx 旋转 180 度&#xff0c;会变成下面的图像 只是把图像转了一下&#xff0c;函数还是那个函数&#xff0c;还是 yex &#xff0c;此时横轴变成了 y 轴&#xff0c;纵轴变成了 x 轴 根据习惯&#xff0c;一般把纵轴当作因变量、把横轴…