回文分区的这种算法的时间复杂度是多少?
What's the time complexity of this algorithm for Palindrome Partitioning?
回文分区
给定一个字符串s,将s划分为Partition是一个回文。
返回所有可能的回文s.分割
我个人认为,时间复杂度是O(n^n), n是给定字符串的长度。
谢谢你Dan Roche,紧时间复杂度= O(n* (2^n)),详情请看下面。
#include <vector>
using namespace std;
class Solution {
public:
vector<vector<string>> partition(string s) {
vector<vector<string>> list;
vector<string> subList;
// Input validation.
if (s.length() <= 1) {
subList.push_back(s);
list.push_back(subList);
return list;
}
int len = s.length();
vector<vector<bool>> memo(len, vector<bool>(len));
for (int i = 0; i < len; i ++) {
for (int j = 0; j < len; j ++) {
if (i >= j) memo[i][j] = true;
else memo[i][j] = false;
}
}
int start = 0;
helper(s, start, list, subList, memo);
return list;
}
void helper(string s, int start,
vector<vector<string>> &list, vector<string> &subList,
vector<vector<bool>> &memo) {
// Base case.
if (start > s.length() - 1) {
vector<string> one_rest(subList);
list.push_back(one_rest);
return;
}
for (int len = 1; start + len <= s.length(); len ++) {
int end = start + len - 1;
memo[start][end] = (len == 1) ||
(memo[start + 1][end - 1] && s[start] == s[end]);
if (memo[start][end] == true) {
// Have a try.
subList.push_back(s.substr(start, len));
// Do recursion.
helper(s, end + 1, list, subList, memo);
// Roll back.
subList.pop_back();
}
}
}
};
应为0 (n*2^n)。你基本上是在尝试每一个可能的分区。对于长度为n的字符串,你将有2^(n - 1)种方法来划分它。这是因为,一个分区相当于在b/t中放入一个"|"两个字符。有n - 1个这样的槽可以放置"|"。每个槽只有两种选择-放置"|"或不放置"|"。因此有2^(n - 1)种方式放置"|"。
然后,对于每个唯一分区,您必须遍历整个字符串(在最坏的情况下,当您有重复字符时),以确保每个分区都是回文。所以n*2^ (n - 1) = O(n*2^n)
最坏情况下的运行时间为O(n * 2^n)。这当然是指数的,正如你所怀疑的,但没有O(n^n)那么糟糕。
我是这样得到O(n * 2^n)的:你的顶层函数有一个O(n^2)循环来初始化memo,然后在整个字符串上调用helper。所以如果我们把H(n)写成在(s.length()-start)
等于n的情况下调用helper的代价,那么你的算法的总代价将是
成本= H(n) + O(n^2)
H(n)的基本情况是当s.length() - start
= 1时,然后它只是复制列表的成本:
H(1) = O(n)
对于递归情况,如果if
条件memo[start][end]
每次都是true
,则会有(n-1), (n-2), (n-3),…, 2, 1。除了这些对helper
的递归调用之外,您还必须在相同的大小上调用substr
函数,总共花费O(n^2)。所以当n>1时,H(n)的总代价是
H(n) = H(n-1) + H(n-2) +…+ H(1) + O(n^2)
(我想写一个总结,但SO没有LaTeX支持)
现在您可以为H(n-1)编写相同的表达式,然后将其代回简化为:
H(n) = 2 H(n-1) + O(n)
结果是
H(n) = O(n * 2^n)
因为它大于O(n^2),所以总代价也是O(n * 2^n)
注意:您可以通过在单个O(n^3)循环中预先计算所有子字符串来略微改进这一点。您也可以对memo
数组执行相同的操作。然而,这并不改变渐近大0界。
实际上,O(n * 2^n)是最优的,因为在最坏的情况下,字符串是相同字符重复n次,如"aaaaaa",在这种情况下,有2^n个可能的分区,每个分区的大小为n,总输出大小为Ω(n * 2^n)。
- while循环中while循环的时间复杂度是多少
- 函数的时间复杂度是多少?
- 将树节点添加到向量向量中的 n 元树遍历的平均和最坏情况时间复杂度是多少?
- 给定C++代码的时间复杂度是多少?
- 将数组的元素插入映射的时间复杂度是多少?
- 以下递归代码的时间复杂度是多少?
- 在C++中修改字符串的BigO时间复杂度是多少
- 这个算法的运行时间复杂度是多少?你是如何分析的
- 此特定代码的时间复杂度是多少?
- % 运算符的时间复杂度C++是多少?
- 三和算法的时间复杂度是多少
- 以下代码片段的时间复杂度是多少?
- 用于搜索的给定代码的时间复杂度是多少
- std::map的时间复杂度是多少
- 遍历二维数组的时间复杂度是多少
- 这个代码(来自leetcode)的时间复杂度是多少
- 以下代码的时间复杂度是多少
- 这个算法的时间复杂度是多少
- 以下循环的时间复杂度是多少
- 一个清晰的函数的时间复杂度是多少,根据大 O,是 std::map