双指针

   双指针指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。我们为什么要使用双指针呢?因为很多问题通过多个指针访问可以降低时间复杂度。一个恰当的算法可以降低程序运行时间;对于数据的维护,我们一般则会根据数据的特点使用对应的数据结构进行维护。这也是为什么人们常说程序 = 算法 + 数据结构,当然这并不全面(狗头保命.jpg)。那么我们该如何利用双指针来处理问题呢(或者说在什么样的问题上我们应当先想到双指针呢)?在处理双指针的问题上,关键是先通过问题要求找出双指针的移动策略(类似于临界条件)。比如快指针移动几步,对应着慢指针才移动,也就是满足什么条件下慢指针才移动。在处理有序问题上,应当首先想到双指针。在处理无序问题上,我们大多时候较难找到双指针的移动策略,所以可以先将无序问题转化为有序问题,再利用双指针进行处理。
  这里给出一道例题,我们使用双指针来解决该问题。(题目来源于leetcode,632最小区间)

  在看到题目的时候,我的想法是先把k个列表先处理为1个列表,因为k个列表不好维护,直接对k个列表进行考虑会增大思维难度,同时时间复杂度也会相应增加。
  这里使用案例进行解释。
  输入:[[4,10,15,24,26],[0,9,12,20],[5,18,22,30]] (version-1)
  处理:[0,4,5,9,10,12,15,18,20,22,24,26,30] (version-1.5)
  但是这样处理我们会发现无法得知处理后的列表中的某个数来源于哪个列表,造成信息遗漏。为了保证信息完整,我们可以使用键值对(Key,Value)来维护数据,Key表示数值,Value表示数值来源于哪个列表。题外话:对于动态规划来说,保证信息完整是一件特别重要的事情,保证信息的完整才能保证状态转移方程式的正确性。
  再次处理:[(0,1),(4,0),(5,2),(9,1),(10,0),(12,1),(15,0),(18,2),(20,1),(22,2),(24,0),(26,0),(30,2)] (version-2)
  这样处理信息的完整性得到保证,同时我们观察到数据存在有序性,于是我们可以使用双指针进行处理。按照上文所说的处理方法,先找出双指针的移动策略。题目要求使得k个列表中的每个列表至少有一个数包含在最小区间中,所以我们可以让快指针先进行移动,而慢指针移动的条件是在快慢指针对应的区间中(快指针在前面,慢指针在后面,对应着一个快慢指针形成的区间)k个列表中的每个列表至少有一个数包含在其中。需注意这里指针只遍历Key,我们保存Value是为了考虑双指针的移动策略什么时候满足。思路大致这样,接下来回到具体操作上。
  现在回来考虑如何将k个列表处理为1个列表上,我们如何将(version-1)处理为(version-2)呢?上面我们说过,可以使用键值对来保证信息完整。键值对?好像懂了?这意味着我们可以采用哈希表(HashMap<Key,Value>)来维护数据。那么具体如何处理呢?我们可以遍历k个数组,遍历每个元素时将每个元素信息放进哈希表中。
  对数据进行预处理之后我们该如何使用双指针进行扫描呢?
  首先,我们先确定双指针的遍历范围,题目要求找出最小区间,那么我们可以确定最小值为k个列表中的最小值,最大值亦是如此。最小值和最大值的区间对应着快指针的遍历区间。
  然后怎么判断什么时候移动策略已经满足了呢(即什么时候在快慢指针对应的区间中k个列表中的每个列表至少有一个数包含在其中)?
  我们可以这样处理,在遍历区间的时候,如果包含HashMap的Key,我们便遍历对应的Value(此时为List),我们可以设置k个桶,编号为0至k-1,每个桶初始为空,即桶的值为0。同时设置number来记录记录有多少个列表至少存在1个数在快慢指针对应的区间中,number初始为0。遍历List时,将List元素的值对应的编号的桶的值加1。每当桶的值为1时,则说明该桶编号对应的列表编号存在1个数在该区间中(快慢指针对应的区间),此时number加1。
  当number的值等于k时,说明已满足移动策略,此时慢指针移动一步(在某些情况下慢指针移动多步,视具体条件判断)。需注意,当慢指针移动一步时,上一步慢指针对应的列表编号所对应的桶值需减1。当快指针达到遍历范围最大值时,遍历结束。

  这里有些细节需要处理,因为在Key相同时,Value无法储存不同的值。所以我们这里采用链表来维护Key相同,而Value不同的情况。具体数据结构为HashMap<Key,List>。
最后附上代码:


posted @ 2020-10-02 12:20  Polaris_Coding  阅读(374)  评论(0编辑  收藏  举报