0x01 基础算法
基础算法
排序
快速排序
思想:分治
- 确定分界点:
q[l],q[(l+r)/2],q[r]
- 调整范围:
q[]<=x,q[]>=x
- 递归处理左右两段
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];
//不能令 mid=l+r>>1 因为 q[mid] 可能会被交换
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);
//用 j 做边界时,x 不能取 q[r]; 用 i 做边界时,x 不能取 q[l] (stagement fault)
quick_sort(q, j + 1, r);
}
归并排序
分治
- 确定分界点
mid=(l+r)/2
- 递归排序左右两边
- 归并:合二为一
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;
while(i<=mid&&j<=r)
if(q[i]<=q[j]) temp[k++]=q[i++];
else temp[k++]=q[j++];
while(i<=mid) temp[k++]=q[i++];
while(j<=r) temp[k++]=q[j++];
for(i=l,j=0;i<=r;i++,j++) q[i]=temp[j];
}
二分
整数二分
- 本质:边界,某一性质在左半边满足,在右半边不满足
- 步骤
- 取
mid
二分,判断mid
点是否满足 - 选择区间,判断是否包括边界
- 递归得到答案
- 取
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
浮点数二分
不需处理边界
bool check(double x) {/* ... */} // 检查 x 是否满足某种性质
double bsearch_3(double l, double r)
{
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
while (r - l > eps)//也可以写 for(int i=0;i<100;i++) ,即将范围除以 2^100 ,精度足够高
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
return l;
}
高精度
输入输出
string a,b;
vector<int>A,B;
cin>>a>>b;//a="123456"
for(int i=a.size()-1;i>=0;i--)
A.push_back(a[i]-'0');//A = [6,5,4,3,2,1]
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--)
printf("%d",C[i]);
高精度加法
vector<int> add(vector<int> &A, vector<int> &B)
{
if (A.size() < B.size()) return add(B, A);
vector<int> C;
int t = 0;
for (int i = 0; i < A.size(); i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
if (t) C.push_back(t);
return C;
}
高精度减法
bool cmp(vector<int> &A,vector<int> &B)//比较大小
{
if(A.size()!=B.size())
return A.size()>B.size();
for(int i=A.size()-1;i>=0;i--)
if(A[i]!=B[i])
return A[i]>B[i];
return true;
}
vector<int> sub(vector<int> &A, vector<int> &B)
{
if(!cmp(A,B))
{
cout<<"-";
return sub(B,A);
}
vector<int> C;
for (int i = 0, t = 0; i < A.size(); i ++ )
{
t = A[i] - t;
if (i < B.size()) t -= B[i];
C.push_back((t + 10) % 10);
if (t < 0) t = 1;
else t = 0;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
高精度乘法
vector<int> mul(vector<int> &A, int b)//高精乘低精
{
vector<int> C;
int t = 0;//进位
for (int i = 0; i < A.size() || t; i ++ )
{
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
高精度除法
vector<int> div(vector<int> &A, int b, int &r)//高精除低精
{
vector<int> C;
r = 0;
for (int i = A.size() - 1; i >= 0; i -- )
{
r = r * 10 + A[i];
C.push_back(r / b);
r %= b;
}//aaaaa/bb=00cdef
reverse(C.begin(), C.end());//fedc00
while (C.size() > 1 && C.back() == 0) C.pop_back();//fdec
return C;
}
前缀和
前缀和:\(S_i=a_1+a_2+...a_i\)
for(i=1;i<=n;i++)//求前缀和
S[i]=S[i-1]+a[i];
cin>>a>>b;cout<<S[b]-S[a-1]<<endl;//算部分和
\(\sum_{i=a}^b{a_i}=S_b-S_{a-1}\)
前缀和能快速计算区间和
a[l]~a[r]
,累加复杂度O(n) ,而前缀和复杂度O(1)首项为\(a_1\)能更好地处理边界问题,令\(S_0=0\),则\(\sum_{i=1}^n{a_i}=S_n-S_0\)
二维前缀和:\(S_{x,y}=\sum_{i=1}^x{\sum_{j=1}^y{a_{i,j}}}\)
for(int i=1;i<=n;i++)//求前缀和
for(int j=1;j<=m;j++)
S[i][j]=S[i-1][j]+S[i][j-1]-S[i-1][j-1]+a[i][j];
cin>>x1>>y1>>x2>>y2;
cout<<S[x2][y2]-S[x1-1][y2]-S[x2][y1-1]+S[x1-1][y1-1]<<endl;//算部分和
- \(\sum_{i=x_1}^{x_2}{\sum_{j=y_1}^{y_2}{a_{i,j}}}=S_{x_2,y_2}-S_{x_2,y_1-1}-S_{x_1-1,y_2}+S_{x_1-1,y_1-1}\)
差分
前缀和的逆运算
差分:构造\({\{b_n\}}\)使得\(a_n=\sum_{i=1}^n{b_i}\),即\(b_i=a_i-a_{i-1}\),则\({\{b_n\}}\)为\({\{a_n\}}\)的差分,\({\{a_n\}}\)为\({\{b_n\}}\)的前缀和
- 差分能快速进行区间更新,将复杂度从O(n)降到O(1)
//为区间 [l,r] 的所有元素加上 c
B[l]+=c;B[r+1]-=c;
//通过差分求原数列
for(int i=1;i<=n;i++)
{
b[i]+=b[i-1];
cout<<b[i];
}
二维差分:\(b_{i,j}=a_{i,j}-a_{i-1,j}-a_{i,j-1}+a_{i-1,j-1}\)
//为区间 (x1,y1) 到 (x2,y2) 的所有元素加上 c
B[x1,y1]+=c,B[x2+1,y1]-=c,B[x1,y2+1]-=c,B[x2+1,y2+1]+=c;
//通过差分求原数列
for(int i=1;i<=n;i++)
{
b[i]+=b[i-1];
cout<<b[i];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
cout<<b[i][j]<<" ";
}
cout<<endl;
}
双指针算法
- 核心思想:两个指针同时操作数据结构,将复杂度从\(O(n^2)\)降至\(O(n)\)
for(i=0,j=0;i<n;i++)
{
while(j<i&&check(i,j)) j++;
//每道题具体逻辑
}
位运算
n>>k&1;//n 的二进制表示的第 k 位
for(int k=n;k>=0;k--) cout<<(n>>k&1);//转换为二进制表示
lowbit(x)=x&-x;//返回 x 的最后一位 1
while(x) x -=(x & -x),tot++;//统计 x 中 1 的个数
离散化
将大范围数据映射到小范围数据
vector<int> alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去掉重复元素
// 二分求出 x 对应的离散化的值
int find(int x) // 找到第一个大于等于 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; // 映射到 1, 2, ...n
}
区间合并
快速合并有交集的区间
- 按区间左端点排序
- 从左往右维护区间,若下一区间左端点小于等于该区间右端点,归并区间;若下一区间左端点大于等于该区间右端点,纳入答案
typedef pair<int,int> PII;
const int M = -2e9;//边界
void merge(vector<PII> &segs)
{
vector<PII> res;
sort(segs.begin(), segs.end());
int st = M, ed = M;
for (auto seg : segs)
if (ed < seg.first)
{
if (st != M) res.push_back({st, ed});
st = seg.first, ed = seg.second;
}
else ed = max(ed, seg.second);
if (st != M) res.push_back({st, ed});
segs = res;
}
0x01 基础算法的更多相关文章
- PHP基础算法
1.首先来画个菱形玩玩,很多人学C时在书上都画过,咱们用PHP画下,画了一半. 思路:多少行for一次,然后在里面空格和星号for一次. <?php for($i=0;$i<=3;$i++ ...
- 10个经典的C语言面试基础算法及代码
10个经典的C语言面试基础算法及代码作者:码农网 – 小峰 原文地址:http://www.codeceo.com/article/10-c-interview-algorithm.html 算法是一 ...
- Java基础算法集50题
最近因为要准备实习,还有一个蓝桥杯的编程比赛,所以准备加强一下算法这块,然后百度了一下java基础算法,看到的都是那50套题,那就花了差不多三个晚自习的时间吧,大体看了一遍,做了其中的27道题,有一些 ...
- 贝叶斯公式由浅入深大讲解—AI基础算法入门
1 贝叶斯方法 长久以来,人们对一件事情发生或不发生的概率,只有固定的0和1,即要么发生,要么不发生,从来不会去考虑某件事情发生的概率有多大,不发生的概率又是多大.而且概率虽然未知,但最起码是一个确定 ...
- 贝叶斯公式由浅入深大讲解—AI基础算法入门【转】
本文转载自:https://www.cnblogs.com/zhoulujun/p/8893393.html 1 贝叶斯方法 长久以来,人们对一件事情发生或不发生的概率,只有固定的0和1,即要么发生, ...
- java入门学习(3)—循环,选择,基础算法,API概念
1.顺序结构:也就是顺着程序的前后关系,依次执行.2.选择分支:利用if..else , / switch(){case [ 这个必须是常量]:}; / if..else if….. ….else.. ...
- Java - 冒泡排序的基础算法(尚学堂第七章数组)
/** * 冒泡排序的基础算法 */ import java.util.Arrays; public class TestBubbleSort1 { public static void main(S ...
- c/c++面试总结---c语言基础算法总结2
c/c++面试总结---c语言基础算法总结2 算法是程序设计的灵魂,好的程序一定是根据合适的算法编程完成的.所有面试过程中重点在考察应聘者基础算法的掌握程度. 上一篇讲解了5中基础的算法,需要在面试之 ...
- c/c++面试指导---c语言基础算法总结1
c语言基础算法总结 1 初学者学习任何一门编程语言都必须要明确,重点是学习编程方法和编程思路,不是学习语法规则,语法规则是为编程实现提供服务和支持.所以只要认真的掌握了c语言编程方法,在学习其它的语 ...
- ACM基础算法入门及题目列表
对于刚进入大学的计算机类同学来说,算法与程序设计竞赛算是不错的选择,因为我们每天都在解决问题,锻炼着解决问题的能力. 这里以TZOJ题目为例,如果为其他平台题目我会标注出来,同时我的主页也欢迎大家去访 ...
随机推荐
- spring-springMVC-总结列表
Spring 的优良特性 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API 控制反转:IOC--Inversion of Control,指的是将对象的创建权交给 Spri ...
- iScroll4中事件点击一次却触发两次解决方案
iScroll是我们在做手机网页中常用的滑动控件之一.单说其功能已相当丰富.但个别时候也是会掉坑的,正好这次就遇上了.在android的app中嵌入网页时不少手机会出现一次点击两次触发的现象.经过一段 ...
- 《Linux shell 脚本攻略》第1章——读书笔记
目录 文件描述符及重定向 函数和参数 迭代器 算术比较 文件系统相关测试 字符串进行比较 文件描述符及重定向 echo "This is a sample text 1" > ...
- 让你看懂dart中静态成员和继承
静态属性和静态方法 在dart中,我们可以通过关键字 static来定义静态属性和静态方法. 需要注意的是: 静态方法不能访问非静态属性[结论1] 非静态方法可以访问静态成员[结论2] 我们通过下面的 ...
- nginx 编译安装及配置解析
一.编译安装 安装插件 安装需要的组件 yum -y install gcc gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel ...
- 表治理-Iceberg元数据合并-metadata.json文件
一.背景描述 元数据文件随时间增多,导致查询变慢.通过如下方式可以指定metadata个数,超过指定数量自动清理. metadata文件对应Iceberg概念是Snapshots 二.解决方案 1.在 ...
- NOIp 2024 考试策略
无论简不简单,都要在前 30min 浏览所有题面,思考哪题可做.哪题不可做,思考能打哪些部分分,9:00 再开始写 T1. 题目简单时 9:00 开写后,30min 以内切完 T1. 9:30 开 T ...
- LLM探索:离线部署Ollama和one-api服务
前言 之前已经在Linux服务器上使用Ollama部署了DeepSeek 这次在没有外网(应该说是被限制比较多)的服务器上部署,遇到一些坑,记录一下 ollama ollama 自然无法使用在线安装脚 ...
- ABB机器人伺服电机维修有脉冲输出时不工作怎么处理
1.ABB机器人伺服电机维修有脉冲输出时不工作怎么处理? 监督操控器的脉冲输出当时值以及脉冲输出灯是否闪烁,承认指令脉冲现已履行并现已正常输出脉冲:查看操控器到驱动器的操控电缆,动力电缆,编码器电缆是 ...
- AWS - [01] 概述
题记部分 001 || 概述 AWS,全称Amazon Web Services,是亚马逊公司旗下的云计算服务平台,自2006年起向全球用户提供广泛而深入的云计算服务.AWD是全球最全面.应用最广 ...