选择三个点的方法,使其最远两点之间的距离小于等于 L


题目要求我们计算选择三个点的方案数,使得这三个点中最远两点之间的距离小于等于 L,其中 L 是一个给定的正整数。

题目中给定一个位于 x 轴上的不同点的数组和一个大于 0 的整数 L。任务是找到三点集合的个数,其中最远两点之间的距离小于等于整数 L。

注意:点集的顺序可以与数组中给定的顺序不同。

我们可以通过以下示例更好地理解这个问题。

输入

a[] = {5, 6, 7, 8}
L=3

输出

4

解释:从给定数组中,最远两点距离小于等于 3 的三点集合如下:

{5, 6, 7},{5, 6, 8},{5, 7, 8} 和 {6, 7, 8}。

集合中最远两点之间的距离从不会超过三倍。

由于点集的顺序可以任意,{5,6,7} 和 {5,7,6} 被认为是相同的。

输入

a[] = {3, 5, 6, 9}
L=3

输出

1

解释:由于三元组中最远两点之间的距离最多只能为 3。只有一个可能的三元组,即 {3, 5, 6}。

我们可以使用不同的方法在 C++ 中解决上述问题。让我们从朴素方法到高效解决方案来研究解决问题的方法。

方法一

这是解决问题的基本策略。该方法的目标是检查给定数组中可能存在的每个三元组,并确定最远两点之间的距离是否小于等于 L 的指定值。如果最远两点之间的距离小于等于 L,则计数三元组;否则,我们将寻找更多三元组。这将为我们提供所有选择三个点的方案,使最远两点之间的距离小于等于 L。

按照以下步骤,我们可以将此方法实现到我们的代码中

  • 对给定数组进行排序,以便在给定数组中迭代时,我们可以检查每个可能的三元组,使得 a[i]<a[i+1]<a[i+2]。

  • 声明一个名为 count=0 的变量来计算可能的三元组数,其最远两点距离小于等于 L。

  • 使用三个嵌套循环遍历整个数组,用于从第一循环中的 x=0、第二循环中的 y=x+1 和第三循环中的 z=y+1 开始的每个三元组。

  • 如果我们找到任何满足 a[z]-a[x]<=L 的三元组,我们将计数加 1 并继续遍历数组以寻找下一个可能的三元组。

  • 遍历整个数组,从 i=0 到 i<数组大小-2,以检查所有可能的三元组,我们可以找到所有选择三个点的方法,使最远两点距离 <=L。

示例

//C++ code to find number of ways of choosing triplet

#include <bits/stdc++.h>

using namespace std;

//function to count the number of ways of choosing three points
int triplets(int a[], int N, int L){
   
   int count =0; //to count the total number of ways
   
   sort(a,a+N); //sorting the array using in-buit sort() function
   
   //iterating in the nested loops to check every triplet
   for(int x=0;x<N-2;x++){
      for(int y=x+1;y<N-1;y++){
         for(int z=y+1;z<N;z++){
            int furthest = a[z] - a[x];
            if(furthest<=L){ //if distance between the furthest points <=L
               count += 1; //increasing count by 1
            }
         }
      }
   }
   
   return count;  //return the possible number of ways satisfying the condition
}

int main()
{
   int a[] = {10, 2, 3, 7, 13, 9};
   int L=5;
   
   int N= sizeof(a)/sizeof(a[0]); //to calculate size of array
   
   cout<<"Total triplets possible : "<<triplets(a, N, L)<<endl;

   return 0;
}

输出

Total triplets possible : 3

时间复杂度:O(N^3),其中 N 是给定数组的大小。

空间复杂度:O(1),因为我们没有使用任何额外的空间。

方法二(高效方法)

上述朴素方法的高效解决方案可以使用二分查找。我们将简单地从 i=0 迭代到 i<数组大小的数组。对于数组中存在的每个元素,我们将找到大于 a[i] 并小于等于 a[i]+L 的点数。为了找到所有可能的三元组 a[i],其中最远两点之间的距离小于等于 L,我们可以使用组合。

$\mathrm{^n{C_{r}}=\frac{n!}{(n-r)!r!}}$ 其中 n 将是大于 a[i] 并小于等于 a[i]+L 的点数,r 将是 2,因为我们想要选择两个点来构成一个可能的三元组。

因此,替换 n 和 r 的值,我们可以写成

三元组数 = 点数 * (点数 - 1)/2

使用这种方法,我们可以找到满足数组中每个元素(即 a[i])条件的每个可能的三元组。

按照以下步骤在 C++ 中实现该方法

  • 我们将创建一个函数来计算可能的三元组数。

  • 之后,对给定数组进行排序以应用二分查找,使用 C++ 中的 sort() 函数。

  • 遍历整个数组,从 i=0 到 i<数组大小-2,计算每个元素的可能三元组。

  • 对于每个元素 a[i],使用 C++ 中的 upper_bound 库查找第一个大于 a[i]+L 的元素的索引,该库返回指向范围内大于传递值的索引的指针。

  • 为了找到大于 a[i] 并小于等于 L 的点数,用大于 a[i]+L 的点的索引减去 i+1。

  • 如果大于 a[i] 并 <=a[i]+L 的点数大于或等于 2,则可以使用上面推导出的公式计算最远点距离 <=L 的可能三元组数,即点数 * (点数 - 1)/2。

  • 计算给定数组中每个元素的每个可能的三元组,其中最远两点之间的距离 <=L。

示例

//C++ code to calculate number of possible ways to choose triplet using binary search
#include<bits/stdc++.h>

using namespace std;

//function to print the total triplets possible where distance
//between the furthest points <=L
int triplets(int a[], int N, int L)
{
   sort(a, a + N); //sort the array using sort() function
   
   int count = 0; //to count the number of ways possible
   
   
   for (int i = 0; i <= N-2; i++) {
       //using upper bound function to find the index greater than a[i]+L
     int index = upper_bound(a, a + N,a[i] + L) - a; 
     
      int x = index - (i + 1); //number of points
      
      if (x >= 2) {
         
         count += (x * (x - 1) / 2); 
      }
   }
   //return the total ways
   return count;
}

int main()
{
   int a[] = {4,7,3,9,8,10};
   int L = 6;
     
   int N = sizeof(a) / sizeof(a[0]); //to calculate the size of the array
  
   cout<<"Total triplets possible : "<<triplets(a, N, L)<<endl; //calling the function
   
   return 0;
}

输出

Total triplets possible: 16

时间复杂度:O(NlogN),其中 N 是数组的大小。

空间复杂度:O(1),因为没有使用额外的空间。

结论

阅读完这篇文章后,我希望你对这个问题的所有概念都已清楚。

更新于:2023年8月21日

146 次查看

开启你的职业生涯

完成课程获得认证

开始学习
广告