leetcode
leetcode 501 ~ 550
数组嵌套

数组嵌套

难度:

标签:

题目描述

代码结果

运行时间: 85 ms, 内存: 23.8 MB


/*
 * 思路:
 * 1. 使用Stream API构建解决方案。
 * 2. 使用一个布尔数组visited来记录某个元素是否已经在集合S中。
 * 3. 如果已经在集合S中,停止当前集合的构建。
 * 4. 使用map和max来计算最大集合的长度。
 */
 
import java.util.stream.IntStream;
 
public int arrayNesting(int[] nums) {
    boolean[] visited = new boolean[nums.length];
    return IntStream.range(0, nums.length)
                    .filter(i -> !visited[i])
                    .map(i -> {
                        int start = nums[i], count = 0;
                        while (!visited[start]) {
                            visited[start] = true;
                            start = nums[start];
                            count++;
                        }
                        return count;
                    })
                    .max()
                    .orElse(0);
}

解释

方法:

这个题解使用了一种类似深度优先搜索的方法。对于每个未访问过的元素,我们从该元素开始,不断访问下一个元素,直到回到已访问过的元素形成一个环,统计环的长度。在访问过程中,将已访问的元素标记为None,避免重复访问。最后返回所有环中最大的长度。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在这个算法中使用`nums[temp] = None`来标记已访问的元素,而不是使用一个额外的数组或集合来存储已访问的元素?
在这个算法中直接在原数组`nums`内部使用`None`来标记已访问的元素,主要是为了节省额外的空间。使用额外的数组或集合来跟踪访问状态会导致空间复杂度增加,从O(1)变为O(n),其中n是数组的长度。此外,直接修改原数组可以使算法实现更为简洁,并且直接操作原数组还可以减少一些内存的申请和访问时间,从而在一定程度上优化性能。
🦆
在算法描述中提到,每个未访问过的元素最多访问一次直到形成环,你如何保证形成环的检测是准确的,即如何确定何时一个元素已经在当前正在构建的环中被访问过?
此算法利用了`nums[temp] = None`来标记已经访问过的元素。在追踪每个元素的时候,如果遇到`nums[current]`已经是`None`,说明当前元素之前已被访问,并且已经成为某个环的一部分。这样就可以确定当前的遍历已经形成了一个环,并且可以立即停止当前环的遍历。这个过程确保了每个元素只被访问一次,且能够准确识别出环的形成。
🦆
这种方法中提到的深度优先搜索(DFS)与传统的DFS在概念或实现上有何区别?
传统的深度优先搜索(DFS)通常用于图的遍历,它使用递归或栈来实现对图的深度探索。在传统DFS中,通常有一个显式的访问标记结构(如访问数组或集合)来防止重复访问。而在这个算法中,虽然也是深入探索直到无法继续(形成环),但是它通过修改原数组来标志访问过的元素,省去了额外的空间使用,并且算法的实现更为简洁。此外,这种方法更专注于追踪环的长度,而不是探索所有可能的路径。
🦆
如果在数组`nums`中存在多个独立的环,这种方法如何确保可以找到所有这些环并正确计算出最大的环的长度?
算法通过从数组的每个索引开始追踪来确保不会遗漏任何一个环。对于每一个未被标记为`None`的索引,算法都会从该索引出发,尝试形成一个环,并且记录这个环的长度。如果形成的环长度超过当前记录的最大长度,则更新最大长度。由于每个元素在整个算法过程中只被访问和标记一次,我们可以保证算法会探索数组中的每个可能的环,从而找到并返回所有环中最大的长度。

相关问题

嵌套列表加权和

嵌套列表加权和

扁平化嵌套列表迭代器

给你一个嵌套的整数列表 nestedList 。每个元素要么是一个整数,要么是一个列表;该列表的元素也可能是整数或者是其他列表。请你实现一个迭代器将其扁平化,使之能够遍历这个列表中的所有整数。

实现扁平迭代器类 NestedIterator

  • NestedIterator(List<NestedInteger> nestedList) 用嵌套列表 nestedList 初始化迭代器。
  • int next() 返回嵌套列表的下一个整数。
  • boolean hasNext() 如果仍然存在待迭代的整数,返回 true ;否则,返回 false

你的代码将会用下述伪代码检测:

initialize iterator with nestedList
res = []
while iterator.hasNext()
    append iterator.next() to the end of res
return res

如果 res 与预期的扁平化列表匹配,那么你的代码将会被判为正确。

 

示例 1:

输入:nestedList = [[1,1],2,[1,1]]
输出:[1,1,2,1,1]
解释:通过重复调用 next 直到 hasNext 返回 false,next 返回的元素的顺序应该是: [1,1,2,1,1]

示例 2:

输入:nestedList = [1,[4,[6]]]
输出:[1,4,6]
解释:通过重复调用 next 直到 hasNext 返回 false,next 返回的元素的顺序应该是: [1,4,6]

 

提示:

  • 1 <= nestedList.length <= 500
  • 嵌套列表中的整数值在范围 [-106, 106]

嵌套列表加权和 II

嵌套列表加权和 II