数组中的双指针技术/算法

96 阅读3分钟

在这篇文章中,我们解释了数组中的双指针技术/算法,它被用来有效地解决大量的问题。问题包括反转数组和查找排序数组中是否存在给定和的一对:

目录:

  1. 双指针技术简介
  2. 例题1:反转一个数组
  3. 例题2:查找一个排序数组中是否存在给定和的一对

让我们开始学习双指针技术。

双指针技术简介

双指针技术是一种广泛使用的技术,用于解决基于数组的各种问题。这对排序数组特别有用,可以帮助解决各种各样的问题。顾名思义,我们使用2个 "指针",指向数组中的某些元素。指针根据一些条件(取决于问题)进行操作,直到它们相遇(可能会有所不同)。

双指针方法本质上使用了2个指针。这些指针可以根据使用情况以不同的方式使用。比如说。

  • 一个指针可以是慢速运行的,而另一个指针可以是快速运行的。这种技术通常被广泛用于基于链接列表的问题。

  • 一个指针指向第一个元素,另一个指针指向数组的最后一个元素。用于处理排序数组的问题。

让我们通过一个问题实例来更好地理解这种技术。请注意,双指针方法有多种应用,并不限于这个具体问题。

例题1:反转一个数组

给定一个数组,我们需要将其反转: arr = [2,5,3,7,4]
反转的arr = [4,7,3,5,2 ]

解决这个问题的一个常用方法是使用2个指针的方法。一个指针指向第一个元素,第二个指针指向最后一个元素。指针所指向的元素被交换,指向第一个元素的指针被递增,而指向最后一个元素的指针被递减(Condition for manipulation)。这个过程一直持续到指针相遇(停止的条件)。

代码

以下是在Java中使用双指针技术的实现:

public static void reverseArray(int arr[], int n)
{
    int  i = 0, j = n-1;
    while(i < j)
    {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        i++;
        j--;
    }
}

以下是在C++中使用双指针技术的实现:

void reverseArray(int arr[], int n)
{
    int  i = 0, j = n-1;
    while(i < j)
    {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        i++;
        j--;
    }
}

时间和空间复杂度

时间复杂度是O(N),因为数组只被遍历了一次。
空间复杂度是O(1),没有使用辅助空间。

例题2:在一个已排序的数组中找出具有给定总和的一对数组是否存在

给定一个已排序的数组和一个数字K,我们需要找到是否存在一对元素,使它们的总和等于给定的数字K.解决这个问题有多种方法(有些方法比其他方法更有效)。

我们将讨论一种使用2个指针的方法作为关键算法的解决方案。

请注意,数组是经过排序的。

例子:
arr = [1,4,5,7,10], K = 12

对(5,7)产生的和等于12. 干运行 。

  • i = 0, j = 4 => arr[i] + arr[j] = 11, 小于12,因此i++
  • i = 1, j = 4 => 4 + 10 = 14 and 14 > K, decrement j,j--.
  • i = 1, j = 3 => 4 + 7 = 11 and 11 < K, 增加i,i++.
  • i = 2, j = 3 => 5 + 7 = 12,等于给定的和K,返回true

算法

  1. 我们使用两个指针,一个指向第一个元素(我们称之为i),另一个指向最后一个元素(我们称之为j)。

  2. 2.2.

    1 如果sum == K,返回true。

    2 如果sum < K, 递增 i。

  3. 返回false。

在这种情况下,这种采用2个指针方法的逻辑是有效的,因为,数组是排序的。
当sum < K时,我们增加i,它开始指向一个比当前元素大的数字。这增加了总和,并可能使其接近(甚至超过)K。然而,任何比当前元素小的数字都会导致总和变小,这肯定会小于K。

同样,当总和>K时,递减j也是有意义的,因为递减j会使总和比以前小,因为使用的新元素比当前元素小。

代码

以下是在Java中使用双指针技术的实现:

    public static boolean pairExists(int arr[], int K)
    {
        int  i = 0, j = arr.length - 1;
        while(i < j)
        {
            if(arr[i] + arr[j] == K)
                return true;
            
            else if(arr[i] + arr[j] < K)
                i++;
            else
                j--;
        }
        return false;
    }

以下是在C++中使用双指针技术的实现。

bool pairExists(int arr[], int n, int K)
{
    int  i = 0, j = n-1;
    while(i < j)
    {
        if(arr[i] + arr[j] == K)
            return true;
        else if(arr[i] + arr[j] < K)
            i++;
        else
            j--;
    }
    return false;
}

时间和空间的复杂性

使用双指针方法有助于将时间复杂性降低到O(N)。我们只需对数组进行一次遍历,就能发现数组中是否存在具有给定和的配对。

这种方法不需要任何辅助空间,因此,空间复杂性为O(1)。

通过OpenGenus的这篇文章,你一定对阵列中的双指针技术有了一个完整的概念,以及如何使用它来解决问题。