内容:
1、two pointers简介
two pointers是算法编程中一种非常重要的思想,它更倾向于一种编程技巧,为我们编程提供了非常高的算法效率。
2、a+b=M
以一个例子引入:给定一个递增的正整数序列和一个正整数M,求序列中的两个不同位置的数a和b,使得他们的和恰好为M,输出所有满足条件的方案。
最直接的方法:
使用二重循环枚举序列A和B,找到这样的a和b,使他们的和为M。
for(int i=0;i
这种做法的时间复杂度是O(n^2)级别的,对于我们算法要求是完全不够的。
复杂度高的原因:
对于已经确定的A[i],如果满足A[i]+B[j]>M,显然也会有A[i]+B[j+1]>M的,这是因为这是个递增序列,即无论如何增加j都是无法得到和为M了,导致j进行了大量的无效枚举。
使用two pointers降低复杂度到O(n)
算法步骤:
代码如下:
while(i
时间复杂度为O(n),显然,相对第一种做法大大优化了算法效率。可以发现,two pointers的思想充分利用了序列递增的性质,以很浅显的思想降低了复杂度。
3、序列合并问题
假如有两个递增序列A和B,要求它们合并为一个递增序列C。
算法过程:
代码如下:
int merge(int A[],int B[],int C[],int n,int m){
int i=0,j=0,index=0;
while(i
4、归并排序
归并排序的思想其实很简单,概括说来,就是“二分排序,有序合并”。将一个序列二分为两个子序列,让这两个子序列去完成各自的排序工作后再合并为一个序列;同时这个子序列也是可以执行同样的操作,再将自己二分为两个规模更小的子序列,排序再合并,直到规模为1是结束。
(1)、归并排序的递归实现——2—路归并排序
排序函数实现:
int mergeSort(int arr[],int l,int r){//传入数组,左边第一个元素和右边最后一个元素
if(l
合并已经排序完成的序列操作实现:
void merge(int arr[],int l,int mid,int r){
int i=l,j=mid+1;
int temp[maxn],index=0;
while(i
(2)、非递归实现
2—路归并排序的非递归实现主要考虑到这样一点:每次分组时组内元素个数上限都是2的幂次。
于是就有了这样的思路:
代码如下:
void mergeSort(int arr[]){
for(int step=2;step/2<=n;step*=2){
for(int i=1;i<=n;i+=step){
int mid=i+step/2-1;
if(mid+1<=n){
merge(arr,i,mid,min(i+step-1,n));
}
}
}
}
当然,如果题目只要求给出归并排序每一趟结束时的序列,那么完全可以使用sort函数来代替merge函数(只要时间限制允许),如下所示:
sort(arr+i,arr+min(i+step,n+1));
5、快速排序
快速排序的算法思想是,记首元素地址arr[0],将后面的元素逐一划分,大于arr[0]的元素放在右边,小于arr[0]的元素放在左边;形成两个子序列,再将子序列重复上述操作,直到子序列规模很小时,也就是递归到底时,两边就会直接形成有序序列,整个序列自然而然也就是有序序列了。
那么我们第一步是要实现元素的划分
代码如下:
void partition(int arr[],int l,int r){
int temp=arr[l];
while(ltemp)
r--; //反复左移r
arr[l]=arr[r];
while(l
第二步是实现快速排序
void quickSort(int arr[],int l,int r){
if(r>l){
int pos=Partition(arr,l,pos-1);
quickSort(arr,l,pos-1);
quickSort(arr,pos+1,r);
}
}
快速排序再最坏时时间复杂度是O(n^2),即当序列接近有序时。
总结:应用好two pointers是编程提高效率的一种重要途径!!!
不忘初心,方得始终!