📜  算法中的时空权衡

📅  最后修改于: 2021-10-23 07:59:19             🧑  作者: Mango

在本文中,我们将讨论算法中的时空权衡。权衡是一件事增加而另一件事减少的情况。这是一种解决问题的方法:

  • 要么在更短的时间内使用更多空间,要么
  • 在很小的空间里花费很长时间。

最好的算法是帮助解决需要更少内存空间并且生成输出所需时间更少的问题。但一般来说,同时满足这两个条件并不总是可能的。最常见的条件是使用查找表的算法。这意味着可以写下每个可能值的某些问题的答案。解决此问题的一种方法是写下整个查找表,这样可以让您非常快速地找到答案,但会占用大量空间。另一种方法是在不写任何东西的情况下计算答案,这占用很少的空间,但可能需要很长时间。因此,您拥有的算法时间效率越高,空间效率就越低。

时空权衡的类型

  • 压缩或未压缩数据
  • 重新渲染或存储的图像
  • 较小的代码或循环展开
  • 查找表或重新计算

压缩或未压缩数据可以对数据存储问题应用时空权衡。如果存储的数据是未压缩的,则需要更多的空间但更少的时间。但是如果数据是压缩存储的,那么运行解压算法需要的空间更少,但时间更长。在许多情况下,可以直接使用压缩数据。在压缩位图索引的情况下,使用压缩比不压缩更快。

重新渲染或存储图像在这种情况下,仅存储源并将其渲染为图像将占用更多空间但时间更少,即,将图像存储在缓存中比重新渲染更快,但需要更多内存空间。

较小的代码或循环展开较小的代码在内存中占用较少的空间,但它需要很长的计算时间,这需要在每次迭代结束时跳回到循环的开头。循环展开可以以增加二进制大小为代价来优化执行速度。它在内存中占用更多空间,但需要更少的计算时间。

查找表或重新计算在查找表中,实现可以包括整个表,这减少了计算时间但增加了所需的内存量。它可以重新计算,即根据需要计算表条目,增加计算时间但减少内存需求。

例如:在数学术语中,斐波那契数列F n由递推关系定义:

使用递归从上述递归关系中找到第N斐波那契项的简单解决方案。

下面是使用递归的实现:

C++
// C++ program to find Nth Fibonacci
// number using recursion
#include 
using namespace std;
 
// Function to find Nth Fibonacci term
int Fibonacci(int N)
{
    // Base Case
    if (N < 2)
        return N;
 
    // Recursively computing the term
    // using recurrence relation
    return Fibonacci(N - 1) + Fibonacci(N - 2);
}
 
// Driver Code
int main()
{
    int N = 5;
 
    // Function Call
    cout << Fibonacci(N);
 
    return 0;
}


Java
// Java program to find Nth Fibonacci
// number using recursion
class GFG {
 
    // Function to find Nth Fibonacci term
    static int Fibonacci(int N)
    {
        // Base Case
        if (N < 2)
            return N;
 
        // Recursively computing the term
        // using recurrence relation
        return Fibonacci(N - 1) + Fibonacci(N - 2);
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int N = 5;
 
        // Function Call
        System.out.print(Fibonacci(N));
    }
}
 
// This code is contributed by rutvik_56.


C#
// C# program to find Nth Fibonacci
// number using recursion
using System;
class GFG
{
 
  // Function to find Nth Fibonacci term
  static int Fibonacci(int N)
  {
 
    // Base Case
    if (N < 2)
      return N;
 
    // Recursively computing the term
    // using recurrence relation
    return Fibonacci(N - 1) + Fibonacci(N - 2);
  }
 
  // Driver Code
  public static void Main(string[] args)
  {
    int N = 5;
 
    // Function Call
    Console.Write(Fibonacci(N));
  }
}
 
// This code is contributed by pratham76.


C++
// C++ program to find Nth Fibonacci
// number using recursion
#include 
using namespace std;
 
// Function to find Nth Fibonacci term
int Fibonacci(int N)
{
    int f[N + 2];
    int i;
 
    // 0th and 1st number of the
    // series are 0 and 1
    f[0] = 0;
    f[1] = 1;
 
    // Iterate over the range [2, N]
    for (i = 2; i <= N; i++) {
 
        // Add the previous 2 numbers
        // in the series and store it
        f[i] = f[i - 1] + f[i - 2];
    }
 
    // Return Nth Fibonacci Number
    return f[N];
}
 
// Driver Code
int main()
{
    int N = 5;
 
    // Function Call
    cout << Fibonacci(N);
 
    return 0;
}


输出:
5

时间复杂度: O(2 N )
辅助空间: O(1)

说明:由于对同一个子问题一次又一次的多次计算,上述实现的时间复杂度是指数级的。使用的辅助空间最小。但我们的目标是降低该方法的时间复杂度,即使它需要额外的空间。下面是讨论的优化方法。

高效方法:为了优化上述方法,其思想是使用动态规划通过记忆重叠子问题来降低复杂性,如下递归树所示:

下面是上述方法的实现:

C++

// C++ program to find Nth Fibonacci
// number using recursion
#include 
using namespace std;
 
// Function to find Nth Fibonacci term
int Fibonacci(int N)
{
    int f[N + 2];
    int i;
 
    // 0th and 1st number of the
    // series are 0 and 1
    f[0] = 0;
    f[1] = 1;
 
    // Iterate over the range [2, N]
    for (i = 2; i <= N; i++) {
 
        // Add the previous 2 numbers
        // in the series and store it
        f[i] = f[i - 1] + f[i - 2];
    }
 
    // Return Nth Fibonacci Number
    return f[N];
}
 
// Driver Code
int main()
{
    int N = 5;
 
    // Function Call
    cout << Fibonacci(N);
 
    return 0;
}
输出:
5

时间复杂度: O(N)
辅助空间: O(N)

说明:上述实现的时间复杂度是线性的,通过使用辅助空间来存储重叠子问题的状态,以便在需要时可以进一步使用。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程