两指针扫描算法举例

问题一:求sum值

描述:给定一有序序列ary和sum值,求序列中是否存在两元素e1和e2,其和刚好为sum。

算法思想:
这是典型的两指针的用法。
i指针从头部开始,j指针从尾部开始,相向移动,
本质向讲,在移动过程中比较ary[i]+ary[j]与sum的大小,达到逐步排除元素的过程,缩短查找范围。
最开始,i和j处于序列首部和尾部
如果ary[i]+ary[j]=sum,直接返回结果。
如果ary[i]+ary[j]<sum,需要增大ary[i]或者ary[j],但是j已经不能在增大,只能i++,因此ary[i]永远被排除掉,缩短了查找范围,
然后在新的序列范围中,继续排除元素逐步缩短查找范围。
如果ary[i]+ary[j]>sum,需要减小ary[i]或者ary[j],但是i已经不能在减小,只能j--,因此ary[j]永远被排除掉,缩短了查找范围,
然后在新的序列范围中,继续排除元素逐步缩短查找范围。

从归纳法的角度看,不难发现,在缩短序列范围的过程中只能是i++或者j--,i只能想后一定吗,j只能向前一定,不能回溯。

java实现:

    public static boolean search(int[] ary,int low,int high,int sum){
        int i = low,j = high;//一前一后两指针
        while(i<j){//两指针i,j不能碰头,这样能够避免sum=2*ary[i]=2*ary[j]的情况
            if (ary[i]+ary[j] < sum) {
                i++;
            }else if(ary[i]+ary[j] > sum){
                j--;
            }else {
                return true;
            }
        }
        return false;
    }

问题二:数组原地去重

描述:给定一重复元素ary,包含若干重复元素,求数组中不重复元素的个数的原地算法,可修改元素组。

Java实现:

/*
     *实现原地数组去重,可改变原数组,返回唯一元素的个数。
     *实际上如果利用额外的辅助空间的话,数组去重的方式有很多,
     *此算法思想的优势就在于只需常数的额外辅助空间,也即是就地算法
     * */
    public static int removeDuplicates(int[] ary,int low,int high){
        int i = low,j = i+1;//两指针,i从low开始,j从i+1开始
        for (; j <= high; j++) {
            if (ary[i] != ary[j]) {
                ary[++i] = ary[j];//i始终记录唯一序列的末尾位置
            }
        }
        return i-low+1;
    }

    /*
     * 如果要求重复元素的个数最多可为n(n>=1)
     * */
    public static int removeDuplicates(int[] ary,int low,int high,int n){
        int i = low+n-1,j = i+1;//i直接从第n个元素开始,j从i+1开始
        for (; j <= high; j++) {
            if (ary[i-n+1] != ary[j]) {//在ary[i]前面且距离为n的元素为ary[i-n+1]
                ary[++i] = ary[j];
            }
        }
        return Math.min(i-low+1, ary.length);
    }

问题三:三色排序

问题描述:输入一个整形的数组,每个元素在0到2之间,其中0,1,2分别代表红色、白色和蓝色。现要求对数组进行排序,相同颜色在一起,而且白色在红色之后,蓝色在白色之后,要求之间复杂度在O(n).

算法思想:
用两指针i和j记录0序列,1序列,2序列的分界位置
只要确定了i和j的值,就可以将三个序列区分开来。
让i指针记录1序列的头部
j指针记录2序列的头部
扫描指针k整个序列头开始扫描,过程中实时更新i和j的值,直到k遇到j位置,此时j后面的元素全为2
i前面的元素全为0,其余元素(i到j之间的元素)全为1。

java实现:

    public static void sort(int[] ary){
        int i = 0,j = ary.length,k = 0;//i记录1序列的头部,j记录2序列的头部,k始终处于1序列尾部的下一个位置
        while(k<j){
            if (ary[k] == 0) {//将ary[k]=0与ary[i]=1交换,此时可以明确知道ary[i]的值
                swap(ary, i++, k++);
            }else if(ary[k] == 1){
                k++;
            }else {//将ary[k]=?与ary[j]=2交换,此时无法知道ary[j--]的值,因此,k保持不变
                swap(ary, k, --j);
            }
        }
    }
时间: 2024-08-04 08:30:49

两指针扫描算法举例的相关文章

算法练习:两指针之三数之和为0

问题描述 给出一个整型数组,找出所有三个元素的组合,其组合之和等于0.要求在结果集里不含有重复的组合. 举例: 输入{-2, 1, -1, 2, 1} 输出{-2, 1, 1 } 问题分析 最容易想到的是穷举法,挑选第一个元素,然后在其后挑选第二个元素,再从除已经挑选出的两个元素之外挑第三个元素,判断三者之和是否为0:第二种想到的是用回溯递归,这两种方法的时间复杂度均为O(n^3),可参阅代码部分关于这两种方法的实现. 那有没有复杂度低一些的呢,答案是有的,就是使用两指针的方法,从而使复杂度下降

多边形扫描算法

一.多边形的扫描转换 一. 1.定义:把多边形的顶点表示转化为点阵表示(就是已知多边形的边界,如何找到多边形内部的点,即把多边形内部填上颜色) 2.表示方法:顶点表示和点阵表示 3.顶点表示:是用多边形的顶点序列来表示多边形. 优点:这种表示直观.几何意义强.占内存少,易于进行几何变换. 缺点:没有明确指出哪些像素在多边形内,故不能直接用于面着色. 4.点阵表示:用位于多边形内的像素集合来刻画多边形 优点:是光栅显示系统显示时所需的表现形式 缺点:丢失了许多几何信息(如边界,顶点等) 5.多边形

[计算机图形学] 基于C#窗口的Bresenham直线扫描算法、种子填充法、扫描线填充法模拟软件设计(一)

一.首先说明: 这是啥? —— 这是利用C#FORM写的一个用来演示计算机图形学中 ①Bresenham直线扫描算法(即:连点成线):②种子填充法(即:填充多边形):③扫描线填充法 有啥用? ——  无论是连点成线还是区域填充在高级编程中基本上都提供很高效的库函数来调用.这里拿出这些算法一方面有利于大家理解那些封装的函数底层是实现:另一方面是方便嵌入式TFT屏幕底层驱动开发时借鉴的. 是啥样? ——  如下面的操作,不言而喻. 二.进入正题: 2-1.直线的扫描转换 图形的扫描转换实质就是在光栅

两指针--减少数组循环

题目(lintcode): 1.二数之和 2.三数之和 3.最接近的三数之和 4.四数之和  取三数之和为例: (一) 普通算法,多重遍历数组,需要多重for嵌套,但严重超时. (二) 剪枝,在外层循环中考虑有没有“不可能符合要求”的情况. 例如,在三数之和中,若两个数之和大于0,直接break.但题目没说不会出现负数,所以不对. (三) 接(二),判断两个数之和大于0无效,是因为数组无序,所以先进行排序  sort(nums.begin(),nums.end()); 之后可以在保证大于0时,b

连通区域标记-行程扫描算法

1.连通域 对于一幅图像来说,它的基本组成单元是像素,每一个像素又对应一个灰度值. 联通区域标记针对的是二值图像,二值图像顾名思义就是它的灰度值只存在两种值---0或255的图像,一个连通区域指的是图像中那些位置相邻,灰度值相同的像素集合所组成的区域. 像素和像素之间的邻域关系有4邻域和8邻域,4邻域指的是当前像素的上下左右位置处的像素,8邻域是指上下左右和对角线位置处的像素. 如右图所示,分别对应的是像素的4邻域和8邻域位置关系   (x,y-1)   (x-1,y) (x,y) (x+1,y

POJ 2187 旋转卡壳 + 水平序 Graham 扫描算法

水平序 Graham 扫描算法: 计算二维凸包的时候可以用到,Graham 扫描算法有水平序和极角序两种. 极角序算法能一次确定整个凸包, 但是计算极角需要用到三角函数,速度较慢,精度较差,特殊情况较多. 水平序算法需要扫描两次,但排序简单,讨论简单,不易出错. [算法流程] 1.对顶点按x为第一关键字,y为第二关键字进行排序. 2.准备一个空栈,并将前两个点压入栈. 3.对于每一个顶点A,只要栈顶中还至少两个顶点,记栈顶为T,栈中第二个为U. 若UT(向量) * TA(向量) <= 0, 则将

opengl实现直线扫描算法和区域填充算法

总体介绍 1.   使用线性扫描算法画一条线,线性离散点 2.   利用区域填充算法画多边形区域,区域离散的点 开发环境VS2012+OpenGL 开发平台 Intel core i5,Intel HD Graphics Family 设计思路 一.直线扫描算法 1.数值微分法(DDA) 已知过端点P0 (x0, y0), P1(x1, y1)的直线段L:y = kx + b,easy得知直线斜率为:k = (y1-y0)/(x1-x0).(如果x1≠x0). 我们如果|k|≤1,这样x每添加1

【转】两种非对称算法原理:RSA和DH

转自:http://blog.chinaunix.net/uid-7550780-id-2611984.html 两种非对称算法原理:RSA和DH 虽然对称算法的效率高,但是密钥的传输需要另外的信道.非对称算法RSA和DH可以解决密钥的传输问题(当然,它们的作用不限于此).这两个算法的名字都是来自于算法作者的缩写,希望有朝一日能够出现用中国人命名的加密算法.非对称算法的根本原理就是单向函数,f(a)=b,但是用b很难得到a. RSA算法 RSA算法是基于大数难于分解的原理.不但可以用于认证,也可

挑子学习笔记:两步聚类算法(TwoStep Cluster Algorithm)——改进的BIRCH算法

转载请标明出处:http://www.cnblogs.com/tiaozistudy/p/twostep_cluster_algorithm.html 两步聚类算法是在SPSS Modeler中使用的一种聚类算法,是BIRCH层次聚类算法的改进版本.可以应用于混合属性数据集的聚类,同时加入了自动确定最佳簇数量的机制,使得方法更加实用.本文在学习文献[1]和“IBM SPSS Modeler 15 Algorithms Guide”的基础上,融入了自己的理解,更详尽地叙述两步聚类算法的流程和细节.