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题目为例,如果为其他平台题目我会标注出来,同时我的主页也欢迎大家去访 ...
随机推荐
- ASP 代码示例,可以生成一个8位随机字符串由字母和数字组成
ChatGP回答的: 下面是一个 ASP 代码示例,可以生成一个8位随机字符串由字母和数字组成: ```Function generateRandomString(length) dim chars, ...
- ffmpeg简易播放器(1)--了解视频格式
视频帧 对于一份视频,实质上是多张图片高速播放形成的.每一张图片即为该视频的一帧.而每秒钟播放的图片张数便为所谓的帧率(Frame Rate/Frame Per Second).常见的帧率有24fps ...
- protocol buffers(protobuf)安装教程
本文按照mac讲解protobuf的安装,windows上比较好安装按照mac的基本流程就可以安装成功,mac上的安装有的时候比较容易出现问题 一.通过brew的方式安装(仅Mac) 需要mac中存在 ...
- Ansible之一module
常用自动化运维工具 Ansible:python,Agentless,中小型应用环境 saltstack:python,一般需部署agent,执行效率更高 puppet:ruby,功能强大,配置复杂, ...
- 闲话 717 - LGV 引理的小应用
这是我们的某一天的联考题目: \(n\le 500\). 显然使用平面图完美匹配计数可以获得 \(O(n^6)\),但是有一种神秘的对路径的双射.当时我们都认为这是超级人类智慧,但是今天看书发现是书上 ...
- 使用guava的cache实现缓存
一.maven <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...
- 用脚本采用wget方式直接下载谷歌云盘里面的文件实操
今天在工作中遇到了一个挑战,在这里和大家分享一下我的解决过程.突然接到一个紧急需求,需要在服务器上部署一个模型文件,而这个文件存储在谷歌云盘里.摆在面前有两个选择: 方案一:先在本地下载,然后再上传到 ...
- C# Web下的类库 项目中获取程序的运行路径
System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase
- JavaScript 浏览本地文件夹
1. JavaScript 浏览本地文件夹 button.onclick = async function () {// 给按钮绑定事件 try { const handler = await sho ...
- 音乐在线刮削容器部署(Music Tag Web)
『音乐标签』Web版是一款可以编辑歌曲的标题,专辑,艺术家,歌词,封面等信息的音乐标签编辑器程序, 支持FLAC, APE, WAV, AIFF, WV, TTA, MP3, M4A, OGG, MP ...