【发布时间】:2015-09-25 01:39:38
【问题描述】:
这是我的代码,用于从一组数字对 (112233 -> 312132) 中生成 Langford 序列。我想写一个递归函数,因为我无法在网上任何地方找到一个递归函数作为使用算法的自我改进练习。我的问题是,如何优化它?有没有办法将动态编程应用于此并具有更好的时间/空间复杂度,并强调时间复杂度?我当前的运行时复杂度为 O(n^2),空间复杂度为 O(n)。在编写更简洁的代码方面的任何帮助也值得赞赏。谢谢。还有,这是一个 P 问题还是一个 NP 问题?
#include <iostream>
using namespace std;
const int arrLen = 8;
const int seqLen = 8;
bool langfordSequence(int * arr, int indx, int *seq, int pos);
int main() {
int arr[] = {1,1,2,2,3,3,4,4};
int seq[] = {0,0,0,0,0,0,0,0};
bool test = langfordSequence(arr, 0, seq, 0);
if (test)
cout << "Langford Sequence Successful: " << endl;
else
cout << "Langford Sequence Failed: " << endl;
for (int i = 0; i < seqLen; i++)
{
cout << seq[i] << " ";
}
return 0;
}
bool langfordSequence(int * arr, int indx, int *seq, int pos)
{
if (indx >= arrLen - 1) //this means we've reached the end of the array
return true;
if (pos + arr[indx] + 1 >= seqLen) //if the second part of the number is off the array
return false;
if (seq[pos] == 0 && seq[pos + arr[indx] + 1] == 0)
{
seq[pos] = arr[indx];
seq[pos + arr[indx] + 1] = arr[indx];
if (langfordSequence(arr, indx + 2, seq, 0)) //the current pair is good, go to the next one, start from the beginning
return true;
else
{
seq[pos] = 0;
seq[pos + arr[indx] + 1] = 0;
if (langfordSequence(arr, indx, seq, pos + 1))
return true;
}
}
else
{
if (langfordSequence(arr, indx, seq, pos + 1)) //current position is no good, try next position
return true;
}
}
【问题讨论】:
-
阅读该问题后首先想到的想法是:如果您可以枚举较低 n 的挂钩序列,则求解较高 n 变成了看你是否可以将两个元素插入到合适大小的间隙中的问题。挂钩序列类似于 121_2 或 2_121。两者都有一个间隙,您可以将 3 插入其中并获得 312132 或 231213。
-
问题空间中还有一个对称性,即任何解决方案的反面都是一个解决方案。
-
你确定你的算法在
O(n^2)时间运行吗?如果我正确理解您的算法,最坏的情况是您尝试将每个输入放在每个可能的位置,直到找到解决方案。那就是O(2^n)运行时间... -
@VincentvanderWeele 你是对的。它是 O(2^n),我仍然掌握测量时间复杂度的窍门。找出递归算法的时间复杂度感觉很棘手。呃,这个算法好慢!
-
@Lorehead 您的意思是不要从第一个位置重新开始,而是跟踪未平仓头寸,看看它们是否直接有效?我已经想到了这一点,但我是否还必须在阵列中搜索才能找到一个空位?也许我可以有另一个数组来存储打开的插槽。 IE。第一个元素存储第一个空槽,第二个元素存储第二个空槽,等等。但我仍然无法使其小于 O(2 ^n) 对吧?
标签: c++ algorithm recursion time-complexity dynamic-programming