代码部分不要翻译,只返回翻译好的部分: 运行时间是 O(n) 还是 O(n * m)?

huangapple go评论62阅读模式
英文:

Is the runtime of my code O(n) or O(n * m)?

问题

 public List<List<Integer>> groupThePeople(int[] groupSizes) {
        List<List<Integer>> groups = new ArrayList<List<Integer>>();
        for(int i = 0; i < groupSizes.length; i++) {
            boolean added = false;
            int index = 0;
            
            while(index < groups.size() && !added) {
                List<Integer> temp = groups.get(index);
                int size = groupSizes[temp.get(0)];
                if(size == groupSizes[i] && temp.size() < groupSizes[i]) {
                    temp.add(i);
                    added = true;
                }
                else {
                    index++;
                }
            }
            
            if(!added) {
                ArrayList<Integer> temp = new ArrayList<Integer>();
                temp.add(i);
                groups.add(temp);
            }
        }
        return groups;
    }

关于你的疑问,这段代码的时间复杂度是 O(n),而不是 O(n * m),其中 n 是输入数组 groupSizes 的长度。尽管有一个内部的 while 循环,但需要注意的是,内部循环的总迭代次数最多只会是输入数组的长度 n,而不是 n * m。因此,这段代码仍然是线性时间复杂度的。

英文:
 public List&lt;List&lt;Integer&gt;&gt; groupThePeople(int[] groupSizes) {
        List&lt;List&lt;Integer&gt;&gt; groups = new ArrayList&lt;List&lt;Integer&gt;&gt;();
        for(int i = 0; i &lt; groupSizes.length; i++) {
            boolean added = false;
            int index = 0;
            
            while(index &lt; groups.size() &amp;&amp; !added) {
                List&lt;Integer&gt; temp = groups.get(index);
                int size = groupSizes[temp.get(0)];
                if(size == groupSizes[i] &amp;&amp; temp.size() &lt; groupSizes[i]) {
                    temp.add(i);
                    added = true;
                }
                else {
                    index++;
                }
            }
            
            if(!added) {
                ArrayList&lt;Integer&gt; temp = new ArrayList&lt;Integer&gt;();
                temp.add(i);
                groups.add(temp);
            }
        }
        return groups;
    }

I am thinking that this code is running at O(n) because I only iterate through the array once, but can it also be O(n * m) because of the inner loop?

答案1

得分: 1

以下是您提供的内容的翻译部分:

似乎在最好的情况下,复杂度可能为 O(N) - 当输入数组 groupSizes 包含 N 个不少于 N 的相同元素,如 {5, 5, 5, 5, 5}, {10, 10,... 10} (10 个元素),等等

如果所有 N 个元素都不同,复杂度为 O(N^2)(实际上是 ~N^2/2) - 这是最坏的情况,当 groupSize 包含 N 个零或一个的时候也可能发生(N > 1)。

更新
通过使用映射将输入数组中的数字存储为键,并将输入数组中的索引收集到列表(二维列表)中,可以重构此代码以提供 O(N) 的复杂度。

最好使用 LinkedHashMap,因为它对插入和获取操作提供 O(1),并保持插入顺序。

public static List<List<Integer>> groupThePeople(int... groupSizes) {
    // System.out.println("plain: " + Arrays.toString(groupSizes));
    Map<Integer, List<List<Integer>>> map = new LinkedHashMap<>();

    for (int i = 0; i < groupSizes.length; i++) {
        // 创建一个二维列表作为给定映射的默认值
        List<List<Integer>> value = map.computeIfAbsent(groupSizes[i], k -> new ArrayList<>(Arrays.asList(new ArrayList<Integer>())));

        // 如果上一个可用的内部列表中没有剩余大小,则需要新的列表
        if (!value.get(value.size() - 1).isEmpty() && groupSizes[i] <= value.get(value.size() - 1).size()) {
            value.add(new ArrayList<>());
        }

        // 将索引添加到内部列表
        value.get(value.size() - 1).add(i);
    }

    return map.values()  // 转换为 Collection<List<List<Integer>>>
              .stream()
              .flatMap(x -> x.stream())
              .collect(Collectors.toList());
}

测试

groupThePeople(0, 1, -1, -1, 3, 3, 3, 1, 2, 3, 0).forEach(System.out::println);

groupThePeople(10, 10, 10, 10, 10, 10, 10, 10, 10, 10).forEach(System.out::println); // 所有数字相同

groupThePeople(10, 15, 15, 15, 10, 10, 10, 10, 10, 10).forEach(System.out::println); // 不拆分嵌套列表

输出:

plain: [0, 1, -1, -1, 3, 3, 3, 1, 2, 3, 0]
[0]
[10]
[1]
[7]
[2]
[3]
[4, 5, 6]
[9]
[8]

plain: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

plain: [10, 15, 15, 15, 10, 10, 10, 10, 10, 10]
[0, 4, 5, 6, 7, 8, 9]
[1, 2, 3]

英文:

It seems that in best case the complexity may be O(N) - when the input array groupSizes contains N identical elements not less than N like {5, 5, 5, 5, 5}, {10, 10,... 10} (10 elements), etc..

If all N elements are different, the complexity is O(N^2) (actually, ~N^2/2) - this is the worst case which is also possible when groupSize contains N zeros or ones (N > 1).

Update<br/>
This code may be refactored to provide O(N) complexity with the help of using a map to store the numbers in the input array as keys and indexes in the input array collected into lists (2D lists) as values.

It's better to use LinkedHashMap because it provides O(1) for insertion and get operations and maintains the order of insertion.

public static List&lt;List&lt;Integer&gt;&gt; groupThePeople(int... groupSizes) {
    // System.out.println(&quot;plain: &quot; + Arrays.toString(groupSizes));
    Map&lt;Integer, List&lt;List&lt;Integer&gt;&gt;&gt; map = new LinkedHashMap&lt;&gt;();
    
    for (int i = 0; i &lt; groupSizes.length; i++) {
        // create a 2D list as a default value for the given map
        List&lt;List&lt;Integer&gt;&gt; value = map.computeIfAbsent(groupSizes[i], k -&gt; new ArrayList&lt;&gt;(Arrays.asList(new ArrayList&lt;Integer&gt;())));

        // new list needed if no size left in the last available inner list
        if (!value.get(value.size() - 1).isEmpty() &amp;&amp; groupSizes[i] &lt;= value.get(value.size() - 1).size()) {
            value.add(new ArrayList&lt;&gt;());
        }

        // add index to the inner list
        value.get(value.size() - 1).add(i);
    }

    return map.values()  // convert Collection&lt;List&lt;List&lt;Integer&gt;&gt;&gt;
              .stream()
              .flatMap(x -&gt; x.stream())
              .collect(Collectors.toList());
}

Test

groupThePeople(0, 1, -1, -1, 3, 3, 3, 1, 2, 3, 0).forEach(System.out::println);
    
groupThePeople(10, 10, 10, 10, 10, 10, 10, 10, 10, 10).forEach(System.out::println); // all numbers the same
    
groupThePeople(10, 15, 15, 15, 10, 10, 10, 10, 10, 10).forEach(System.out::println); // without splitting nested lists

Output:

plain: [0, 1, -1, -1, 3, 3, 3, 1, 2, 3, 0]
[0]
[10]
[1]
[7]
[2]
[3]
[4, 5, 6]
[9]
[8]

plain: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

plain: [10, 15, 15, 15, 10, 10, 10, 10, 10, 10]
[0, 4, 5, 6, 7, 8, 9]
[1, 2, 3]

Similar approach may be implemented using Stream API, though it seems more verbose.

Also, this implementation is two-pass, the second pass is needed to split the inner lists of indexes into sublists with the size less than the key number.

public static List&lt;List&lt;Integer&gt;&gt; groupThePeopleStream(int... groupSizes) {
    
    // System.out.println(&quot;stream: &quot; + Arrays.toString(groupSizes));
    
    return IntStream
            .range(0, groupSizes.length)
            .mapToObj(i -&gt; Map.entry(groupSizes[i], i)) // entry: number -&gt; index
            .collect(Collectors.groupingBy(Map.Entry::getKey, LinkedHashMap::new, // convert to map: number -&gt; list of indexes
                        Collectors.mapping(Map.Entry::getValue, Collectors.toList())))
            .entrySet()
            .stream()
            //.peek(e -&gt; System.out.println(e.getKey() + &quot;:&quot;))
            .flatMap(e -&gt; e.getKey() &gt;= e.getValue().size() // need to split list of indexes?
                    ? Stream.of(e.getValue())       // no, store a single index
                    : IntStream.iterate(0, x -&gt; x &lt; e.getValue().size(), x -&gt; x + Math.max(1, e.getKey())) // yes, preparing indexes: 0, N, 2N..
                               .mapToObj(x -&gt; e.getValue().subList(x, Math.min(x + Math.max(1, e.getKey()), e.getValue().size())))
            )
            //.peek(x -&gt; System.out.println(&quot;\t&quot; + x))
            .collect(Collectors.toList());
}

Output for the same test data (including debug prints):

stream: [0, 1, -1, -1, 3, 3, 3, 1, 2, 3, 0]
0:
	[0]
	[10]
1:
	[1]
	[7]
-1:
	[2]
	[3]
3:
	[4, 5, 6]
	[9]
2:
	[8]

stream: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
10:
	[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

stream: [10, 15, 15, 15, 10, 10, 10, 10, 10, 10]
10:
	[0, 4, 5, 6, 7, 8, 9]
15:
	[1, 2, 3]

huangapple
  • 本文由 发表于 2020年10月19日 23:30:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64430495.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定