在本文中,我们将讨论算法中的时空权衡。权衡是一种情况,一件事增加而另一件事减少。这是解决以下问题的一种方法:
- 花费更少的时间并使用更多的空间,或者
- 在很小的空间中花费大量时间。
最好的算法是有助于解决以下问题的算法,该问题需要较少的内存空间并且还需要较少的时间来生成输出。但是总的来说,并非总是能够同时达到这两个条件。最常见的条件是使用查找表的算法。这意味着可以写下一些有关每个可能值的问题的答案。解决此问题的一种方法是写下整个查找表,这将使您很快找到答案,但会占用大量空间。另一种方法是在不写下任何内容的情况下计算答案,这虽然占用很少的空间,但是可能会花费很长时间。因此,您拥有的时间效率更高的算法将节省空间。
时空权衡的类型
- 压缩或未压缩的数据
- 重新渲染或存储图像
- 较小的代码或循环展开
- 查找表或重新计算
压缩或未压缩的数据:时空折衷可以应用于数据存储问题。如果存储的数据未压缩,则将占用更多空间,但所需时间更少。但是,如果将数据压缩存储,则需要较少的空间,但是会花费更多的时间来运行解压缩算法。在许多情况下,可以直接使用压缩数据。在压缩位图索引的情况下,使用压缩比不使用压缩要快得多。
重新渲染或存储图像:在这种情况下,仅存储源并将其渲染为图像会占用更多空间,但所需时间更少,即,将图像存储在缓存中比重新渲染更快,但需要更多的内存空间。
较小的代码或循环展开:较小的代码在内存中占用较少的空间,但是它需要很高的计算时间,这是在每次迭代结束时跳回到循环的开始所需要的。循环展开可以以增加二进制大小为代价来优化执行速度。它在内存中占用更多空间,但需要更少的计算时间。
查找表或重新计算:在查找表中,实现可以包括整个表,这样可以减少计算时间,但会增加所需的内存量。它可以重新计算,即根据需要计算表条目,从而增加了计算时间,但减少了内存需求。
例如:用数学术语,斐波纳契数的序列F n由递归关系定义:
Fn = Fn – 1 + Fn – 2,
where, F0 = 0 and F1 = 1.
根据上述递归关系使用递归找到第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)
说明:上述实现的时间复杂度是线性的,方法是使用辅助空间来存储重叠的子问题状态,以便在需要时可以进一步使用它。