如何使用动态编程有效地解决最长几何级数的问题

122 阅读5分钟

在这篇文章中,我们解释了如何使用动态编程有效地解决最长几何级数的问题。它涉及到使用地图数据结构来实现,这与其他标准问题不同。

目录

  1. 问题陈述。最长几何级数
  2. 天真方法
  3. 动态编程法

我们可以通过Naive Approch或动态编程来解决这个问题(我们必须使用Map of Float Map<Float, Integer>)。

问题陈述:最长的几何级数

什么是几何级数?

如果一个元素的序列遵循以下模式,它就是一个几何级数。

a,a\*r,a\*r2,a\*r3,...,a\*rN,...a, a \* r, a \* r^2, a \* r^3, ..., a \* r^N, ...

其中:

  • a是几何级数的第一个元素
  • a\*ri1a \* r^{i-1} 是几何级数的第1个元素。

在解决最长几何级数的问题之前,让我们先举个例子:

A = {2, 4, 8, 10, 50, 250}

所以,在这里我们发现了两个几何级数,一个是共同的比例2,另一个是5。
是的,每两个数字都会在几何级数中,所以我们要讨论的是超越这一点。

  • a_1a\_1: 2 4 8 , r=2
  • a_2a\_2: 2 10 50 250 , r=5

所以,我们的答案应该是4(a=2的大小)。

为了更好地理解这个问题,我们需要观察几何级数的一些特性。当且仅当三个数字持有属性时,它们可以是几何级数。

如果a、b、c都在几何级数中。

b2=a\*cb^2= a \* c
或者我们可以说b/a=c/bb/a = c/b

天真的方法

在Naive方法中,我们将遵循以下步骤:

  1. 首先对数组进行排序。这将花费O(NlogN)O(N logN)时间
  2. 通过一个循环,从第一个索引开始,然后再嵌套一个循环来选择下一个元素的进展
  3. 现在在最内层循环中,我们将检查所有具有相同公比的元素

时间复杂度:O(N3)O(N^3)

动态编程方法

算法

动态编程的结构将是:

DP[i][j] = LGP with the first element 
           being array[i] and ratio being j

LGP = 最长的几何级数

如果有两个元素array[i]和array[j]的比率为R,并且与之前的元素对相比没有共同比率,那么:

DP[i][R] = 1

否则,如果前面的元素之间有共同的比率R,那么:

DP[i][r] = DP[j][r] + 1

答案是矩阵DP[][]中的最大值。

为了以最小的空间有效地实现这一技术,你需要使用一个Map数据结构。

使用动态编程找到最长的几何级数的步骤。

  1. 首先对所有元素进行排序,这样我们就可以很容易地跟踪具有相同公比的元素的数量。
  2. 初始化一个数组类型(map<double,int>),数组的长度是给定集合的大小。
  3. 使用两个循环,一个用于遍历我们的集合,另一个用于检查哪些元素与之前的元素有相同的公比。如果我们能找到相同的共同比率,那么就通过1来增加它,否则就为该地图创建一个具有共同比率的新实体,并以2来初始化它。

一步一步来

A = {5, 10, 20, 30}

所以数组的大小,
int n=A.size()

我们将声明一个地图类型的数组,用来存储具有共同比率(r)的进展的元素数量。

现在,我们认为如何使用动态编程来解决这个问题,我们必须为数组的每个索引维护一个map<float,integer>的列表。

让我们追踪所有数组的索引。

  • 第一个索引的元素:5
    在这个索引之前没有任何元素,所以继续

  • 第二个索引的元素:10

在10之前,我们在第一个索引有一个元素,所以公比r=10/5。由于r=2,我们在第二个索引更新我们的地图list(2)(r)=2。

  • 在第三个索引的元素:20

在这之前,我们在第一个和第二个索引有两个元素。一个是公共比率2,另一个是4。有了这个,我们更新数值如下:

list(3)(2) = list(2)(2) + 1 = 3
list(3)(4) = 2

  • 第四个索引的元素:30

在这里我们得到了之前没有出现过的具有共同比率的元素:

list(4)(3/2) = 2
list(4)(3) = 2
list(4)(6) = 2

所以,在list(3)(2)=3处找到最大值:

答案=3

伪装代码

1: 将浮点数作为地图值,将整数作为关键值,声明
Map<Float,Integer>dp
2: 现在从第一个索引到最后一个索引进行迭代,然后将所有具有共同比率的值,放入地图中并递增
首先检查给定数组的大小让n成为数组的大小,如果(n<=2),那么简单的n就是我们的答案否则我们必须声明一个与数组大小相同的地图Map<Float,Integer>dp(n)

   loop(i=0 to n)
   {
    loop (j=0 to less than i)
    {
      float r=A[i]/A[j]
      Search r in dp[j]
        if r is present in dp[j] then 
         dp[i][r] = dp[j][r] + 1  , because we found one more value which has 
         same common 
         ratio.
        else
        Create an map with defaul value 2
        dp[i][r] =2 ,
       }
   }

现在我们来讨论一下它的各种时间和空间的复杂性...

复杂度

  • 最坏情况下的时间复杂度:Θ(n^2)
  • 平均情况下的时间复杂度:Θ(n^2)
  • 最佳情况下的时间复杂度:Θ(n^2)
  • 空间复杂度:Θ(n^2)

困境:

int findLargestSequence(int A[])
{
int n=sizeof(A)/sizeof(A[0]);
if(n<=2)
    return n;
sort(A,A+n); //first sort all the elements
map<float,int>dp[n]; // declare  a dp array of size n.
int max=0;

for(int i=0;i<n;i++)
{
    for(int j=0;j<i;j++)
    {
        float r=A[i]/A[j];
        if(dp[j].find(r)!=dp[j].end());
        {
            dp[i].insert(make_pair(r,2));
            //sequence has at least two elements with a ratio(r)
        }
        else
        {
            dp[i][r]=dp[j][r]+1;  
            // if at the jth index we already have a sequence with common ratio r
        }
        if(dp[i][r]>max)
            max=dp[i][r];
    }
}
return max;
}

时间和空间复杂度

时间复杂度:O(N2)O(N^2)
空间复杂度:O(N2)O(N^2)

关键点

我们必须对浮动值进行映射,因为公共比率可以是浮动值,也可以是小数,两者都不是。

通过OpenGenus的这篇文章,你一定对最长几何级数有了完整的了解。