0
点赞
收藏
分享

微信扫一扫

基础算法(1)_排序,双指针,离散化

肉肉七七 2022-03-12 阅读 50

快排

主要思想:

选取数列中的一个数x作为标准,将小于x的元素丢在左边,大于x的元素丢在右边;

递归处理将数组不断划分,在子数组里面重复上述步骤

具体措施:

1.定义两个指针(数组下标)分别从左右两端推进,与x对比。左边找大于x的数,右边找小于x的数,找到之后互换位置。

2.递归左右两个数组

具体代码:

void quick_sort(int l,int r)
{
     if(l>=r) return;

    int i=l-1,j=r+1,mid=q[l+r>>1];//这里可以随机取,左右端取,中间取都可以
    //左边大于x,右边小于x的元素,找到了互换位置
    while(i<j)
    {
         while(q[++i]<mid);
         while(q[--j]>mid);
        if(i<j)
        {   int temp;
            temp= q[i];
            q[i]=q[j];
            q[j]=temp;
        }
    }
    //左右数组递归
    quick_sort(l,j),quick_sort(j+1,r);
}

代码里面要注意的是左右数组递归时,j要么与i相等,要么j在i前面一个位置。

划分标准为j时,mid取(l+r>>1);

划分标准为i时,mid取(l+r+1>>1);

若以i为标准,mid取(l+r>>1)两个元素时递归会被写死。可以自己举个例子。

归并

主要思想:

数组先左右划分成子问题,递归处理两个数组。将两个子数组每个元素进行比较,较小的存入临时数组,最后将数组合并。

具体措施:

设置两个指针(数组下标),分别指向左右两个数组,两个数组元素比较,较小的存入临时数组。

最后将临时数组内容放回。

具体代码:

 int temp[N];
void merge_sort(int l, int r,int q[])  // 归并排序
{
   int mid=l+r>>1;
   int i=l,j=mid+1,k=0;
  
   
   if(l>=r) return;
   merge_sort(l,mid,q),merge_sort(mid+1,r,q);//划分子问题
   
   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(int i=l,j=0;i<=r;i++,j++) q[i]=temp[j];
   
}

双指针算法

可以用作双重循环的优化,减少时间复杂度

例子1:最长连续的不重复子序列 【1 2 2 3 5-> 3】

主要思想:

i,j两个指针,i向前记录数组元素,额外开一个数组num记录每个元素出现次数

若出现次数大于1则说明出现重复元素,通过j指针向前移动弹出元素,知道num里面该元素的值小于1.最后取最大i,j之间的长度。

具体措施:

一层for循环让指针i向前移动记录数组,让num数组记录元素出现次数;

内部嵌套while循环,让j指针向前移动,直至弹出重复元素。

具体代码:

    int res;
    for(int i=0,j=0;i<n;i++)
    {
        s[q[i]]++;
        while(s[q[i]]>1)
        {
            s[q[j]]--;
            j++;
        }
        res= max(res,i-j+1);
    }

例子2:给两个升序数组一个目标值,求数组中哪两个元素和等于目标值(数据保证答案唯一)

主要思想:

用暴力解法写两层for循环即可。用双指针算法进行优化,这里双指针算法就是在暴力解法结合题目升序的性质优化。指针i指向A数组前端,指针j指向B数组末端。(防止指针回溯是降低复杂度的关键)

具体措施:

在开始时将j指针指到末尾,若二者和小于x ,继续移动j仍然会小于,此时移动i(增大),
若大于x继续移动j
考虑移动了i之前的j里面会有解吗?
不会  之前的小i加上原来的j都比x大 ,更何况现在是大i了

  for(int i=0,j=m-1;i<n;i++)
  {
      while(A[i]+B[j]>x) j--;
      if(A[i]+B[j]==x) {cout<<i<<" "<<j<<endl;break;}
    
  }

举报

相关推荐

0 条评论