前言
第一周学习内容
一、排序算法
1、快速排序
快速排序分为两个过程:
- 将数列分成两部分(要求保证相对大小关系);
- 递归到两个子序列中并分别进行快速排序;
int partition(int arr[],int low,int high){
int pivot=arr[high];
int i=low-1;
for(int j=low;j<high;j++){
if(arr[j]<=pivot){
i++;
swap(&arr[i],&arr[j]);
}
}
swap(&arr[i+1],&arr[high]);
return i+1;
}
void quickSort(int arr[],int low,int high){
if(low<high){
int pi=partition(arr,low,high);
quickSort(arr,low,pi-1);
quickSort(arr,pi+1,high);
}
}
2、归并排序
核心思想:
将两个有序的数组 a[i]
和 b[j]
合并为一个有序数组 c[k]
。
从左往右枚举 a[i]
和 b[j]
,找出最小的值并放入数组 c[k]
;重复上述过程直
到 a[i]
和 b[j]
有一个为空时,将另一个数组剩下的元素放入 c[k]
。
void merge(int arr[],int left,int mid,int right){
int n1=mid-left+1;
int n2=right-mid;
int L[n1],R[n2];
for(int i=0;i<n1;i++){
L[i]=arr[left+i];
}
for(int j=0;j<n2;j++){
R[j]=arr[mid+1+j];
}
int i=0,j=0,k=left;
while(i<n1&&j<n2){
if(L[i]<=R[j]){
arr[k]=L[i];
i++;
}else{
arr[k]=R[j];
j++;
}
k++;
}
while(i<n1){
arr[k]=L[i];
k++;
i++;
}
while(j<n2){
arr[k]=R[j];
j++;
k++;
}
}
void mergeSort(int arr[],int left,int right){
if(left<right){
int mid=left+(right-left)/2;
mergeSort(arr,left,mid);
mergeSort(arr,mid+1,right);
merge(arr,left,mid,right);
}
}
二、二分法
每次考察数组的中间元素,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,则向右侧查找;如果中间元素大于所查找的值则,向左侧查找。
int erfenchazhao(int nums[],int n,int k,int ret){
int left=0,right=n-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==k){
if(ret){
if(mid==0||nums[mid-1]!=k){
return mid;
}else{
right=mid-1;
}
}else{
if(mid==n-1||nums[mid+1]!=k){
return mid;
}else{
left=mid+1;
}
}
}else if(nums[mid]<k){
left=mid+1;
}else{
right=mid-1;
}
}
return -1;
}
三、前缀和与差分
差分可以当作是一种求和的逆运算。
1、一维前缀和
sum[i]=sum[i-1]+arr[i]
利用前缀和对矩阵某区间进行加减操作
chafen[x]+=c;
chafen[[y+1]-=c;
2、一维差分
arr[i]=sum[i]-um[i-1]
3、二维前缀和
sum[i][j]=sum[i-1][j]+sum[i][j-1]+arr[i][j]-sum[i-1][j-1]
利用前缀和对矩阵某区间进行加减操作
chafen[x][y]+=c;
chafen[x][h+1]-=c;
chafen[z+1][y]-=c;
chafen[z+1][h+1]+=c;
4、二维差分
arr[i][j]=sum[i][j]-sum[i][j-1]-sum[i-1][j]+sum[i-1][j-1]
四、位运算、离散化、双指针
1、位运算
a、左移和右移
num << i
表示将 的二进制表示向左移动 num 位所得的值。
num >> i
表示将 的二进制表示向右移动 num 位所得的值。
b、按位与、或、异或、取反
& | ^ ~
c、求n的第k位数字:
n >> k & 1
d、返回n的最后一位1:
lowbit(n) = n & -n
2、离散化
因为数轴是无限长的,直接存储每个位置的值不现实。所以我们可以使用离散化的方法。
离散化就是把无限空间中有限的个体映射到有限的空间中去,以提高算法的时空效率。
首先,我们把所有操作的位置 和询问的区间端点 、 都收集起来,进行排序去重,这样就得到了一个离散化后的坐标集合。
代码如下:
vector<int> alls;
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end),alls.end);
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;
}
然后,对于每个操作,我们在离散化后的坐标集合中找到对应的位置,进行累加操作。
最后,对于每个询问,我们在离散化后的坐标集合中找到对应的区间,计算这个区间内的累加和。
3、双指针
for(int i=0,j=0;i<n;i++){
while(j<i&&check(i,j)){
j++;
}
}
五、高精度
模拟四则运算
a、高精度加法
void add(int *a,int *b,int *c){
for(int i=0;i<len-1;i++){
c[i]+=a[i]+b[i];
if(c[i]>=10){
c[i+1]+=1;
c[i]-=10;
}
}
}
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;
}
注:vector a,b,c中数字按照从低位到高位存储。
b、高精度减法
void sub(int *a,int *b,int *c){
for(int i=0;i<len-1;i++){
c[i]+=a[i]-b[i];
if(c[i]<0){
c[i+1]-=1;
c[i]+=10;
}
}
}
vector<int> sub(vector<int>&a,vector<int>&b){
int t=0;
vector<int>c;
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);
if(t<0){
t=1;
}else{
t=0;
}
}
while(c.size()>1&&c.back()==0){
c.pop_back();
}
return c;
}
注:vector a,b,c中数字按照从低位到高位存储。
c、高精度乘法
void mul(int *a,int *b,int *c){
for(int i=0;i<len-1;i++){
for(int j=0;j<=i;j++){
c[i]+=a[j]*b[i-j];
if(c[i]>=10){
c[i+1]+=c[i]/10;
c[i]%=10;
}
}
}
}
vector<int> mul(vector<int>&a,int b){
int t=0;
vector<int>c;
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 a,b,c中数字按照从低位到高位存储,默认a>=b>=0。
d、高精度除法
vector<int> div(vector<int>&a,int b,int &r){
vector<int>c;
r=0;
for(int i=0;i<a.size();i++){
r=r*10+a[i];
c.push_back(r/b);
r%=b;
}
reverse(c.begin(),c.end());
while(c.size()>1&&c.back()==0){
c.pop_back();
}
return c;
}
注:vector a,b,c中数字按照从低位到高位存储,默认a>=b,a>=0,b>0。
引用时:
int r=1;
c=div(a,b,r);