当前位置: 首页 > 知识库问答 >
问题:

这个自上而下的动态编程代码的时间复杂度是多少?

游鸣
2023-03-14

我不能像下面的例子那样分析自顶向下动态规划方法的时间复杂性。你能帮帮我吗?

问题:给定一个字符串s和一个字符串字典wordDict,如果s可以被分割成一个或多个字典单词的空格分隔序列,则返回true。注意,词典中的同一个词可能在切分中被重复使用多次。

输入:s=“catsandog”,worddict=[“cats”,“dog”,“sand”,“cat”]
输出:false

输入:s=“leetcode”,worddict=[“leet”,“code”]
输出:true

bool match(string &s,int l,int n,string &wordDict) {
    int i = 0;
    while(l < n && i < wordDict.size()) {
        if (s[l] != wordDict[i])
            return false;
        l++;
        i++;
    }
    return i == wordDict.size();
}
bool wordBreakUtil(string &s, int l, int n, vector<string>& wordDict, map<int,bool> &m) {
    if (l==n)
        return true;
    if (m.find(l) != m.end()) {
        return m[l];
    }
    int i;
    for(i=0;i<wordDict.size();i++) {
        if (match(s,l,n,wordDict[i])) {
            if (wordBreakUtil(s,l+wordDict[i].size(),n,wordDict,m))
                return true;
        }
    }
    m[l] = false;
    return false;
}
bool wordBreak(string s, vector<string>& wordDict) {
    int n = s.size();
    map<int,bool> m;
    return wordBreakUtil(s,0,n,wordDict,m);
}

共有1个答案

空俊语
2023-03-14

通过将递归调用中完成的计算工作与其他工作分开,可以找到memoised DP算法的最坏情况界限。具体来说,我们需要确定:

  1. 使用不同的输入(参数值)调用递归函数的最大可能次数--这是函数必须“完成它的工作”而不是快速返回已经计算好的答案的最大可能次数。
  2. 对递归函数的每次调用中所做的最大工作量,不包括对其本身的递归调用。

然后,我们可以将(1)的答案乘以(2)的答案,得到一个上界。(这个界限可能不是很紧,因为问题中可能存在结构,这意味着实际上避免了递归函数调用的渐近重要数量,或者每个调用中所做的工作量远小于这些调用的渐近重要部分中可能的最大值,或者两者兼而有之--但在实践中,它通常是紧的。)

递归函数wordbreakutil()用6个不同的参数调用,但实际上只有其中一个参数L随每次调用而变化。因为我们在M中记录结果,所以当我们处理以前从未见过的L值时,我们可以保证只将结果传递到函数的主体(for循环):这意味着(1)的答案是WordBreakutil()可以调用的不同的L值的最大数量,即n+1(值0、1、2、...、n)。渐近地,这是O(n)。

假设字典中有k单词。在WordBreakutil()中,它所做的最大工作量(不包括对自身的递归调用)为O(kn)。这是因为它循环k次,每次都调用match()match()在其循环中最多执行n步骤。(您可以将match()的复杂性描述为L,其中L是字典中任何字符串的最大长度,也可以将其更精确地描述为min(n,L),但是添加L参数会使表达式更加复杂,而不会提供太多信息。)对于M.find(l)调用,还有一个log k加法项,但这是由O(kn)项主导的,因此在WordBreakutil()中完成的非递归工作仍然是O(kn)。

这意味着总的执行时间以O(kn^2)为界。

 类似资料:
  • 由于std::sort的时间复杂度为nlog(n),我们有(N1+N2....Nk)次迭代,因此我假设总的时间复杂度为O((N1+N2....+Nk)klog(k))。但是在每次迭代中,vector的大小可能会有所不同,所以我有点困惑。有人能证实这一点吗? 2.我还在leetcode论坛上看到了另一个使用“合并排序”思想的解决方案。它每次都合并两个链表。 我想知道这个解决方案的时间复杂度是多少?因

  • 有人能帮我了解一下这个代码片段的时间和空间复杂性吗?请参考leetcode问题-单词中断II。给定一个非空字符串s和一个包含非空单词列表的字典单词dict,在s中添加空格来构造一个句子,其中每个单词都是有效的字典单词。返回所有这些可能的句子。

  • Leetcode问题https://leetcode.com/problems/count-binary-substrings/ 该解决方案有效,但我很难提出递归解决方案的时间复杂度。 每当循环遇到s.charAt(i)!=s.charAt(i 1)时,它都会进行递归调用以展开,直到达到基本大小写或其他部分。 因为我遍历整个字符串,所以for循环是O(n)。但是如何确定将进行的递归调用的数量,因为

  • 问题内容: 我当时在看这个pycon演讲,时间是34:30,发言人说,可以在中完成获取元素列表中最大的元素的操作。 那怎么可能?我的理解是,创建堆将是,但是其本身的复杂性是还是(以及(实际的算法是什么))? 问题答案: 扬声器在这种情况下是错误的。实际费用为。仅在可迭代的第一个元素上调用堆化。就是那个,但如果小于,则微不足道。然后,将所有剩余的元素一次通过添加到此“小堆”中。每次调用需要花费时间。

  • 我知道嵌套for循环的时间复杂度等于最里面的循环执行的次数。 像外部循环从1到n的每个嵌套循环一样,它应该运行n次,但这里我们有,这使得算法运行的顺序更好。实际上,我在IDE中编写了这段代码,并在循环结束后打印了x的最终结果,对于不同的n值,我看到跳入内部for循环需要将近n倍的时间。 所以我认为这个算法的整个顺序是,但我不确定