简体   繁体   English

用迭代计算递归函数的时间复杂度

[英]Calculating Time Complexity of recursive function with iteration

I am trying to understand the time complexity for this code which calculates IP addresses given a string by splitting the string into 4 parts.我试图了解这段代码的时间复杂度,它通过将字符串分成 4 部分来计算给定字符串的 IP 地址。 Each part is separated by a period ie .每个部分由句点分隔,即.

public List<String> restoreIpAddresses(String s, int parts) {

    List<String> result = new ArrayList<>();
    if (parts == 1) {
        if (isValidPart(s)) result.add(s);
        return result;
    }
    
    for (int i = 0; i < s.length(); i++) {
        String first = s.substring(0, i);
        if (!isValidPart(first)) {
            continue;
        }
        
        List<String> previous = restoreIpAddresses(s.substring(i, s.length()), parts - 1);
        
        for (String str: previous) {
            StringBuilder sb = new StringBuilder();
            result.add(first + "." + str);
        }
    }        
    
    return result;
    
}

private boolean isValidPart(String part) {
    if ( (part.length() > 1 && part.startsWith("0")) || 
         (part.length() > 3) || (part.length() == 0)
         (Integer.valueOf(part) > 255) ) return false;
      return true;
    }
}

Since the for loop is O(n) , n being the length of the string, and in each iteration the for loop executes for the substring that was passed in the parent for loop, so O(n - 1) .由于 for 循环是O(n) ,n 是字符串的长度,并且在每次迭代中,for 循环都会为在父 for 循环中传递的子字符串执行,所以O(n - 1) So by this logic, the time complexity should be n(n-1)(n-2) ....1 ie n!所以按照这个逻辑,时间复杂度应该是n(n-1)(n-2) ....1n! in the worst case, right?在最坏的情况下,对吧?

However if I look around (eg. here or here ), I see people posting constant time complexity.但是,如果我环顾四周(例如herehere ),我会看到人们发布恒定的时间复杂度。 I am unable to understand.我无法理解。 Can someone help me break it down?有人可以帮我分解一下吗?

Consider this for generating the IP adresses from above algorithm we have two constraints.考虑到从上述算法生成 IP 地址,我们有两个约束。

  1. Valid IP is from 0->255.有效 IP 为 0->255。 This can be evaluated in constant time.这可以在恒定时间内进行评估。
  2. There will be 4 octets.将有 4 个八位字节。 So the question string should be divided into 4 parts.所以问题字符串应该分为4部分。

Now consider a string 111 111 111 111 of length 12现在考虑一个长度为12的字符串111 111 111 111

  1. How many way can you form the first octet?你有多少种方式可以形成第一个八位字节? => minimum 1 , maximum 3 ways out of 12 characters. => 最少 1 ,最多 3 种方式,共 12 个字符。 complexity:- O(3)

  2. How many way can you form the second octet?你有多少种方式可以形成第二个八位字节? => minimum 0 maximum 3 ways out of 9 character, considering 3 characters are used by first octet. => 9 个字符中的最小 0 最大 3 种方式,考虑到第一个八位字节使用了 3 个字符。 complexity:- O(3)

  3. How many way can you form the third octet?你有多少种方式可以形成第三个八位字节? => minimum 0 maximum 3 ways from 6 character, considering 6 characters are used by first and second octet. => 最少 0 最多 3 种方式,从 6 个字符开始,考虑到第一个和第二个八位字节使用 6 个字符。 complexity:- O(3)

  4. How many way can you form the fourth octet with the remaining characters?你有多少种方法可以用剩余的字符组成第四个八位字节? => There is only one way to form an octet from the remaining 3 characters. => 只有一种方法可以从剩余的 3 个字符形成一个八位字节。 considering 9 characters are used by the first, second, and third octet.考虑到第一个、第二个和第三个八位字节使用了 9 个字符。 O(1)

Time complexity Calculation.时间复杂度计算。

Time Complexity = product of complexities of each recursive function
                = O(3)*O(3)*O(3)*O(1)
                = 3*O(3) = O(1) = [constant-time] complexity

So no matter what string you will give as an input all the valid IP addresses can be counted in 27 iterations.因此,无论您提供什么字符串作为输入,所有有效 IP 地址都可以计算为27次迭代。 Therefore this algorithm is a constant time O(1) .因此这个算法是一个常数时间O(1)

Considering the above understanding the code can be re-written following way考虑到以上理解,代码可以按照以下方式重写


public static List<String> restoreIpAddresses(String s, int position, int parts) {

        List<String> result = new ArrayList<>();
        // O(1) time complexity
        if (parts == 1) {
            if (position < s.length() && isValidPart(s.substring(position))) {
                result.add(s.substring(position));
            }
            return result;
        }

        // Iterate only thrice in each recursive function. O(3) time complexity
        for (int i = position; i <= position + 3; i++) {
            if (i > s.length()) {
                continue;
            }

            String first = s.substring(position, i);
            if (!isValidPart(first)) {
                continue;
            }

            List<String> previous = restoreIpAddresses(s, i , parts - 1);

            for (String str : previous) {
                StringBuilder sb = new StringBuilder();
                result.add(first + "." + str);
            }
        }

        return result;

    }

Note that the above algorithm is one examples of classic backtracking problems .请注意,上述算法是经典backtracking problems一个例子。 From wiki.来自维基。

Backtracking is a general algorithm for finding solutions to some computational problems, notably constraint satisfaction problems, that incrementally builds candidates to the solutions, and abandons a candidate ("backtracks") as soon as it determines that the candidate cannot possibly be completed to a valid solution回溯是一种通用算法,用于寻找某些计算问题的解决方案,特别是约束满足问题,它逐步构建解决方案的候选者,并在确定候选者不可能完成到有效的时立即放弃候选者(“回溯”)解决方案

PS:- The example 111 111 111 111 is an extreme example and there is only one valid IP 111.111.111.111 address that can be formed from this string. PS:- 示例111 111 111 111是一个极端示例,只有一个有效的 IP 地址111.111.111.111可以从该字符串中形成。 However, the loop/recursion evaluation will happen a maximum of 81 times.但是,循环/递归评估最多会发生 81 次。

Given n , the length of input string and i , the number of parts.给定n ,输入字符串的长度和i ,部分的数量。 the time-complexity of the code is obtained by below formula:代码的time-complexity由以下公式获得:

在此处输入图片说明

The formula is recursive because the code is recursive.该公式是递归的,因为代码是递归的。 On the right hand side, the second Sigma denotes the time-complexity of each for-loop (substring).Moreover, by solving the latter sigma like below:在右侧,第二个 Sigma 表示每个for-loop (子字符串)的time-complexity 。此外,通过求解后一个 Sigma,如下所示:

在此处输入图片说明

we reach to this equation:我们得出这个等式:

在此处输入图片说明

Consider we are at Level-0 and we move to Level-1 .考虑我们在Level-0并且我们移动到Level-1 Therefore, the equation turns to:因此,方程变为:

在此处输入图片说明

Approximately we have (see this link for more info):我们大约有(有关更多信息,请参阅此链接):

在此处输入图片说明

The equation turns to:方程变为:

在此处输入图片说明

if we move at next level which is Level-2 (I just write Simplicable part):如果我们进入下一个级别,即Level-2 (我只写简单部分):

在此处输入图片说明

the equation turns to:方程变为:

在此处输入图片说明

with the help of mathematical induction we can say:借助mathematical induction我们可以说:

在此处输入图片说明

my assumptions and formulations may be wrong.我的假设和表述可能是错误的。 However, I enjoy playing with math.不过,我喜欢玩数学。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM