C++ 递归基转换时间复杂度分析
给定整数C++ 递归基转换时间复杂度分析,c++,algorithm,recursion,numbers,base,C++,Algorithm,Recursion,Numbers,Base,给定整数p和目标基b,在基b中返回p的字符串表示形式。字符串的末尾应具有最低有效位 ^这就是我给自己的问题 我提出的朴素递归算法(在C++中)如下所示: string convertIntToBaseRecursive(int number, int base) { // Base case if (!number) return ""; // Adding least significant digit to "the rest" computed recursively /
p
和目标基b
,在基b
中返回p
的字符串表示形式。字符串的末尾应具有最低有效位
^这就是我给自己的问题
我提出的朴素递归算法(在C++中)如下所示:
string convertIntToBaseRecursive(int number, int base) {
// Base case
if (!number) return "";
// Adding least significant digit to "the rest" computed recursively
// Could reverse these operations if we wanted the string backwards.
return convertToBaseRecursive(number / base, base) + to_string(number % base);
}
虽然算法非常简单,但我想确保我理解复杂性分解。下面是我的想法,我想知道它们是正确的,还是错误的,如果它们是错误的,那么知道我偏离了轨道将是很好的
索赔:
是返回字符串的长度n=logb(p)
- 时间复杂度:
O(n^2)
- 空间复杂度:
O(n)
我们在上面的C++算法中做第一个方法,而
的字符串,下一帧创建长度为n
、n-1
、n-2
的字符串,依此类推。遵循这一趋势(无需证明为什么n-3
),很明显时间复杂度是1+2+3…+n=O(n^2)
。我们也只需要在任何时候将O(n^2)=O(logb^2(p))
内容存储在内存中。当原始堆栈帧解析时(就在算法完成之前)我们将以原始字符串的形式拥有内存,但在它解析之前,它将以单个字符(O(n)
)+递归堆栈帧(O(1)
)的形式存在。我们在每个级别上存储O(n)
数量的单个字符,直到完成为止。因此,空间复杂度是n
O(n)
string convertIntToBaseIterative(int number, int base) {
string retString = "";
while (number) {
retString += to_string(number % base);
number /= base;
}
// Only needed if least significant
reverse(retString.begin(), retString.end());
return retString;
}
我相信上述解决方案,其中n=logb(p)
具有:
- 时间复杂度:
O(n)
- 空间复杂度:
O(n)
这些分析正确吗?或者我在什么地方出错了吗?由于返回值必须包含输出,因此无法获得比
O(n)
更好的空间复杂度
假设输出字符串按顺序由以下数字组成:a_1,a_2,a_3,…,a_n
。在递归方法中,我们创建如下字符串:“a_1”+“a_2”+…+“a_n”
。在迭代方法中,我们做:(((a_1)+a_2)+a_3)++a_n))
。因此,这两种情况下的时间复杂度在O(n^2)
(在C++03中。有关C++11,请参见下面的注释)处应该是相同的
如您所见,这两种方法都受到实现细节的严重影响。字符串
类型对于涉及重复连接的操作不是很有用。如果您有一个大小为n
的预分配数组,您可以将复杂性降低到O(n)
注意1:关于追加操作有一些细节。在C++03中,追加操作没有指定的复杂性,并且可能导致在写入时进行复制(如果字符串不能适当扩展并且需要重新定位)。在C++11中,不允许使用CoW和rope样式的实现,追加应该导致每个字符的摊销时间O(1)
。因此,在C++11的情况下,我们应该能够得到两种实现的时间复杂度
注2:要通过用户定义的字符串实现(包含长度)获得O(n)
时间复杂度,需要在函数中通过引用传递字符串。这将导致函数签名更改为:
void convertToBaseRecursive(int number, int base, MyString& str)
如果字符串使用预先分配的数组,此实现将允许共享和就地更新字符串。由于返回值必须包含输出,因此无法获得比
O(n)
更好的空间复杂度
假设输出字符串按顺序由以下数字组成:a_1、a_2、a_3、…、a_n
。在递归方法中,我们创建如下字符串:“a_1”+“a_2”+…+“a_n”
。在迭代方法中,我们做:(((…(a_1)+a_2)+a_3)+…+a_n))…)
。因此,这两种情况下的时间复杂度在O(n^2)
(在C++03中。有关C++11,请参见下面的注释)处应该是相同的
如您所见,这两种方法都受到实现细节的严重影响。字符串
类型对于涉及重复连接的操作不是很有用。如果您有一个大小为n
的预分配数组,您可以将复杂性降低到O(n)
注意1:关于追加操作有一些细节。在C++03中,追加操作没有指定的复杂性,并且可能导致在写入时进行复制(如果字符串不能适当扩展并且需要重新定位)。在C++11中,不允许使用CoW和rope样式的实现,追加应该导致每个字符的摊销时间O(1)
。因此,在C++11的情况下,我们应该能够得到两种实现的时间复杂度
注2:要通过用户定义的字符串实现(包含长度)获得O(n)
时间复杂度,需要在函数中通过引用传递字符串。这将导致函数签名更改为:
void convertToBaseRecursive(int number, int base, MyString& str)
此实现将允许共享字符串并就地更新,前提是该字符串使用的数组