C++程序 给定排序和旋转的数组,查找是否存在给定和的一对

C++程序 给定排序和旋转的数组,查找是否存在给定和的一对

给定一个排序后,然后围绕一个未知点旋转的数组。查找数组是否具有给定和“x”的一对。可以假定数组中的所有元素都是不同的。

示例:

输入:arr[] = {11, 15, 6, 8, 9, 10},x = 16
输出:true
有一对(6,10)和为16

输入:arr[] = {11, 15, 26, 38, 9, 10},x = 35
输出:true
有一对(26,9)和为35

输入:arr[] = {11, 15, 26, 38, 9, 10},x = 45
输出:false
没有和为45的一对。

我们已经讨论过一种针对排序数组的O(n)解决方法(请参见方法1的步骤2、3和4)。我们也可以将此解决方案扩展到旋转数组上。首先找到数组中最大的元素,这是枢轴点,最大元素后面的元素是最小元素。一旦我们有了最大和最小元素的索引,我们使用类似于中间相遇算法(如方法1中所述)来查找是否存在一对。这里唯一的新事物是使用模运算以旋转方式递增和递减索引。

下面是上述想法的实现。

输出 :

数组有两个元素和为16

上述解的时间复杂度为O(n)。使用二进制搜索方法在O(logn)内优化可以找到枢轴。

如何计算所有和为x的对数?

以下是逐步算法:

  1. 找到排序和旋转数组的枢轴元素。枢轴元素是数组中最大的元素。最小元素将与它相邻。
  2. 使用两个指针(称为left和right),其中左指针指向最小元素,右指针指向最大元素。
  3. 查找指针指向的两个元素的和。
  4. 如果和等于x,则增加计数。如果和小于x,则将左指针按旋转方式递增到下一个位置以增加和。如果和大于x,则将右指针按旋转方式递减到下一个位置以减少和。
  5. 重复步骤3和4,直到左指针不等于右指针或左指针不等于right pointer-1为止。
  6. 打印最终计数。

下面是上述算法的实现。

// C++程序查找给定和的已排序旋转数组中的对数。
#include<bits/stdc++.h>
using namespace std;
 
//此函数返回和等于x的对数。
int pairsInSortedRotated(int arr[], int n, int x)
{
    //查找枢轴元素。 枢轴元素
    //是数组的最大元素。
    int i;
    for (i = 0; i < n-1; i++)
        if (arr[i] > arr[i+1])
            break;
     
    // l是最小元素的索引。
    int l = (i + 1) % n;
     
    // r是最大元素的索引。
    int r = i;
     
    //变量用于存储数字的数量
    //对数。
    int cnt = 0;
 
    //查找由arr [l]和arr [r]形成的对的总和
    //并相应地更新l,r和cnt。
    while (l != r)
    {
        //如果我们找到和为x的一对,则
        //增加计数器,将l和r移动到
        //下一个元素。
        if (arr[l] + arr[r] == x){
            cnt++;
             
            //必须检查此条件,
            //否则l和r将相交,循环
            //永远不会终止。
            if(l == (r - 1 + n) % n){
                return cnt;
            }
             
            l = (l + 1) % n;
            r = (r - 1 + n) % n;
        }
 
        //如果当前对的总和较小,则移动到
        //更高的总和方向。
        else if (arr[l] + arr[r] < x)
            l = (l + 1) % n;
         
        //如果当前对的总和较大,请移动
        //到较低的总和方向。
        else
            r = (n + r - 1)%n;
    }
     
    return cnt;
}
 
/* 主程序来测试上述函数 */
int main()
{
    int arr[] = {11, 15, 6, 7, 9, 10};
    int sum = 16;
    int n = sizeof(arr)/sizeof(arr[0]);
 
    cout << pairsInSortedRotated(arr, n, sum);
     
    return 0;
}  

输出:

2

时间复杂度: O(n)

辅助空间: O(1)

这种方法是由Nikhil Jindal推荐的。

方法:双指针方法

  1. 使用修改后的二分搜索算法查找旋转排序数组的旋转元素。
  2. 初始化两个指针,一个指向数组的最小元素,另一个指向数组的最大元素。
  3. 当左指针小于右指针时,重复步骤4到6。
  4. 计算由左右指针指向的元素的和。
  5. 如果总和等于给定的总和,则返回true。
  6. 如果总和大于给定的总和,则将右指针减少。如果总和少于给定的总和,则将左指针增加。
  7. 如果没有找到给定总和的一对,则返回false。
#include <iostream>
using namespace std;
 
bool pairInSortedRotated(int arr[], int n, int x)
{
    // 使用二分查找找到轴心元素
    int i;
    for (i = 0; i < n - 1; i++)
        if (arr[i] > arr[i + 1])
            break;
 
    // 初始化左右指针
    int left = (i + 1) % n;
    int right = i;
 
    // 查找给定和的对
    while (left != right)
    {
        // 如果找到了给定和的对,返回true
        if (arr[left] + arr[right] == x)
            return true;
 
        // 如果和大于给定和,将右指针减1
        else if (arr[left] + arr[right] > x)
            right = (n + right - 1) % n;
 
        // 如果和小于给定和,将左指针加1
        else
            left = (left + 1) % n;
    }
 
    // 如果找不到给定和的对,返回false
    return false;
}
 
int main()
{
    int arr1[] = {11, 15, 6, 8, 9, 10};
    int n1 = sizeof(arr1) / sizeof(arr1[0]);
    int x1 = 16;
 
    if (pairInSortedRotated(arr1, n1, x1))
        cout << "True";
    else
        cout << "False";
 
    cout << endl;
 
    int arr2[] = {11, 15, 26, 38, 9, 10};
    int n2 = sizeof(arr2) / sizeof(arr2[0]);
    int x2 = 35;
 
    if (pairInSortedRotated(arr2, n2, x2))
        cout << "True";
    else
        cout << "False";
 
    cout << endl;
 
    int arr3[] = {11, 15, 26, 38, 9, 10};
    int n3 = sizeof(arr3) / sizeof(arr3[0]);
    int x3 = 45;
 
    if (pairInSortedRotated(arr3, n3, x3))
        cout << "True";
    else
        cout << "False";
 
    return 0;
}  

输出结果

True
True
False

时间复杂度:O(n)

辅助空间:O(1)

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

C++ 示例