Skip to content

Commit 179108b

Browse files
committed
更新0565. 数组嵌套 题目解析
1 parent bfedda1 commit 179108b

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# [0565. 数组嵌套](https://leetcode.cn/problems/array-nesting/)
2+
3+
- 标签:深度优先搜索、数组
4+
- 难度:中等
5+
6+
## 题目链接
7+
8+
- [0565. 数组嵌套 - 力扣](https://leetcode.cn/problems/array-nesting/)
9+
10+
## 题目大意
11+
12+
**描述**
13+
14+
给定索引从 $0$ 开始长度为 $N$ 的数组 $A$,包含 $0 \sim N - 1$ 的所有整数。
15+
16+
**要求**
17+
18+
找到最大的集合 $S$ 并返回其大小,其中 $S[i] = \{A[i], A[A[i]], A[A[A[i]]], ... \}$ 且遵守以下的规则。
19+
20+
假设选择索引为 $i$ 的元素 $A[i]$ 为 $S$ 的第一个元素,$S$ 的下一个元素应该是 $A[A[i]]$,之后是 $A[A[A[i]]]...$ 以此类推,不断添加直到 $S$ 出现重复的元素。
21+
22+
**说明**
23+
24+
- $1 \le nums.length \le 10^{5}$。
25+
- $0 \le nums[i] \lt nums.length$。
26+
- $A$ 中不含有重复的元素。
27+
28+
**示例**
29+
30+
- 示例 1:
31+
32+
```python
33+
输入: A = [5,4,0,3,1,6,2]
34+
输出: 4
35+
解释:
36+
A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2.
37+
38+
其中一种最长的 S[K]:
39+
S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0}
40+
```
41+
42+
## 解题思路
43+
44+
### 思路 1:
45+
46+
将数组 $A$ 看成一个有向图:每个下标 $i$ 指向唯一的下标 $A[i]$。由于 $A$ 是 $0\sim N-1$ 的一个排列(元素不重复,且都在范围内),图中每个节点出度均为 $1$,因此整张图由若干个「不相交的简单环」组成。题目中的集合 $S[i] = \{A[i], A[A[i]], A[A[A[i]]], \ldots\}$ 实际上就是从起点 $i$ 出发顺着边前进直到首次重复时形成的环,答案即为所有环中最大的长度。
47+
48+
做法:从每个未访问的起点 $i$ 出发,沿着 $i \to A[i] \to A[A[i]] \to \cdots$ 走,并统计本次路径中第一次遇到已访问节点前的步数,即该环的长度。用布尔数组(或集合) $visited$ 标记已经访问过的下标,保证每个下标只被遍历一次。
49+
50+
**变量含义**
51+
52+
- $N$:数组长度。
53+
- $A$:输入数组。
54+
- $visited$:访问标记数组,`visited[x] = True` 表示下标 $x$ 已被计入某个环或已遍历过。
55+
- $ans$:当前找到的最大环长。
56+
- $curr$:从某个起点出发的游标位置。
57+
- $cnt$:从当前起点出发走到重复前累计的长度。
58+
59+
**算法步骤**
60+
61+
1. 初始化 $visited$ 全为 `False`,$ans = 0$。
62+
2. 枚举起点 $i \in [0, N-1]$。若 `visited[i]``True`,跳过;否则从 $i$ 出发:
63+
- 置 $cnt = 0$,$curr = i$。
64+
-`visited[curr]``False` 时:标记 `visited[curr] = True`,令 $curr = A[curr]$,$cnt++$。
65+
- 本轮结束时,更新 $ans = \max(ans, cnt)$。
66+
3. 返回 $ans$。
67+
68+
### 思路 1:代码
69+
70+
```python
71+
class Solution:
72+
def arrayNesting(self, nums: List[int]) -> int:
73+
n = len(nums)
74+
visited = [False] * n # 访问标记:True 表示该下标已被遍历过
75+
ans = 0
76+
77+
for i in range(n):
78+
if visited[i]:
79+
continue # 已处理过,跳过
80+
81+
cnt = 0
82+
curr = i
83+
# 顺着 i -> nums[i] -> nums[nums[i]] ... 直到遇到已访问位置
84+
while not visited[curr]:
85+
visited[curr] = True
86+
curr = nums[curr]
87+
cnt += 1
88+
89+
# 本次从起点 i 出发形成的环长度为 cnt
90+
if cnt > ans:
91+
ans = cnt
92+
93+
return ans
94+
```
95+
96+
### 思路 1:复杂度分析
97+
98+
- **时间复杂度**:$O(N)$。每个下标至多被访问一次。
99+
- **空间复杂度**:$O(N)$。使用了大小为 $N$ 的 $visited$ 辅助数组。

0 commit comments

Comments
 (0)