给定整数
adb shell am broadcast -a com.android.intent.action.SET_LOCALE --es com.android.intent.extra.LOCALE "en_US" com.android.customlocale2
和目标基础p
,在基础b
中返回p
的字符串表示形式。该字符串在末尾应该具有最低有效位
^这是我给自己的问题。
我提出的天真递归算法(在C ++中)如下:
b
虽然算法非常简单,但我想确保理解复杂性故障。我的想法在下面,我想知道他们是否正确或错误,如果他们错了,那么知道我在哪里偏离轨道会很好!
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)
为了将最低有效位保留在字符串的末尾,当它是我们先计算的值之前,我们要么必须:
我们正在使用上述C ++算法中的第一个方法,O(n)
运算符在每个堆栈帧处创建一个新字符串。初始帧创建并返回长度为+
的字符串,下一帧创建长度为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)
这些分析是正确的还是我在某个地方?
答案 0 :(得分:0)
由于返回值必须包含输出,因此无法获得比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)
。因此,两种情况下的时间复杂度应该在string
处相同(在C ++ 03中。请参阅下面的C ++ 11注释)。
如您所见,这两种方法都受到实施细节的严重影响。 n
类型对于涉及重复串联的操作不是很有用。如果您有一个预先分配的大小为O(n)
的数组,则可以将复杂度降低到O(1)
。
注1:有一些关于追加操作的细节。在C ++ 03中,追加操作没有指定的复杂性,并且可能导致Copy-On_write(如果字符串无法扩展到位并且需要重定位)。在C ++ 11中,不允许CoW和绳式实现,并且追加应该导致每个角色分摊O(n)
个时间。因此,在C ++ 11的情况下,我们应该能够为这两种实现获得O(n)
时间复杂度。
注意2 :要使用用户定义的字符串实现(包含长度)获得void convertToBaseRecursive(int number, int base, MyString& str)
时间复杂度,需要在函数中通过引用传递字符串。这将导致函数签名变为:
text-align
如果字符串使用预先分配的数组,此实现将允许字符串共享和更新。
答案 1 :(得分:0)
鉴于聊天室与@user1952500的对话,我根据我们所讨论的内容对他的回答进行了一些编辑。以下是他的答案的编辑版本,反映了我们所谈论的最新内容和我学到的内容:
由于返回值必须包含输出,因此无法获得比O(n)
更好的空间复杂度。
假设输出字符串按顺序由以下数字组成:a_1, a_2, a_3, ..., a_n
。在里面
递归方法(项目符号#1),我们创建一个字符串,如下"a_1" + "a_2" + .... + "a_n"
,其中包含
递归产生O(n^2)
时间复杂度。在子弹#2中,迭代方法不断推动角色
在(((...(a_1) + a_2) + a_3) + ... + a_n)))...)
之类的字符串前面移动整个字符串
每个角色的添加也会产生O(n^2)
时间复杂度。在你的书面迭代方法(子弹#3)
时间复杂度可以根据C ++的版本进行优化(参见下面的注释)。
字符串类型对于涉及重复串联的操作不是很有用。在旧版本的C ++中你
通过预先分配大小为n的字符串可以实现O(n)
时间复杂度。在C ++ 11中this
answer表示某些追加操作可以优化为单个字符的摊销O(1)
。假设
这是真的,写出的迭代版本将具有O(1)
时间复杂度而无需任何额外的工作。
注意:要使用此算法的递归版本获得O(n)时间复杂度,我们可以利用已摊销的O(1)
character追加并使用通过引用传递的单个字符串。这将需要递归版本的函数签名
重写如下:
void convertToBaseRecursive(int number, int base, string& str)