Description
A zero-indexed array A of length N contains all integers from 0 to N-1. Find and return the longest length of set S, where S[i] = {A[i], A[A[i]], A[A[A[i]]], ... } subjected to the rule below.
Suppose the first element in S starts with the selection of element A[i] of index = i, the next element in S should be A[A[i]], and then A[A[A[i]]]… By that analogy, we stop adding right before a duplicate element occurs in S.
Example 1:
Input: A = [5,4,0,3,1,6,2]
Output: 4
Explanation:
A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2.
One of the longest S[K]:
S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0}
Note:
- N is an integer within the range [1, 20,000].
- The elements of A are all distinct.
- Each element of A is an integer within the range [0, N-1].
Solution
HashSet, time O(n), space O(n)
由于题目给定的nums[]中,值是[0, n) distinct的,所以这道题好做很多。
按照题目给定的set形成方式,可以发现,nums[]是由若干条单向有环链表组成的。对于有环链表中每个节点来说,从谁开始长度都不可能超过从当前起点开始。所以可以添加一个visited节点记录当前链表路径上经过的节点,避免重复以它为起点。
class Solution {
public int arrayNesting(int[] nums) {
Set<Integer> visited = new HashSet<>();
int maxLen = 0;
for (int i = 0; i < nums.length; ++i) {
if (visited.contains(i)) {
continue;
}
Set<Integer> set = new HashSet<>(); // store current path
while (set.add(i)) {
i = nums[i];
}
maxLen = Math.max(set.size(), maxLen);
visited.addAll(set);
}
return maxLen;
}
}
Iteration, time O(n), space O(1)
由于nums[]值都是非负且唯一的,所以不可能有两条路径都经过某个相同节点。我们可以将visited节点的值置成负的,从而省略掉visited。
class Solution {
public int arrayNesting(int[] nums) {
int maxLen = 0;
for (int i = 0; i < nums.length; ++i) {
if (nums[i] < 0) {
continue;
}
int count = 0;
while (nums[i] >= 0) {
++count;
int next = nums[i];
nums[i] = -1; // visited flag
i = next;
}
maxLen = Math.max(count, maxLen);
}
return maxLen;
}
}