题目:
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].
依题意可以知道,给定输入的数组有这样的特点:
1、数组中的元素不重复;
2、长度为N的数组中的所有元素大小范围为[0, N-1]。
所以可以得到结论:数组中元素可以按照{A[i], A[A[i]], A[A[A[i]]], ... } 的规则划分为不同的集合,并且所有集合之间都没有交集。
一开始的思路是利用set记录访问过的下表Index,使用for循环遍历数组,如果这个下标访问过则跳过,进行下一个循环;若未访问过则表示找到一个新集合,通过条件si.find(temp) == si.end()判断是否该元素是否已经记录过,若是条件为false则表示元素已经出现重复,停止搜索。
class Solution {
public:
int arrayNesting(vector<int>& nums) {
set<int> si;
int len = nums.size();
int res = 0;
for(int i = 0; i < len; i++){
int cnt = 0;
int temp = i;
while(si.find(temp) == si.end()){
cnt++;
si.insert(temp);
temp = nums[temp];
}
res = max(cnt, res);
if(res > len/2)
break;
}
return res;
}
};
运行的速度较慢:56ms。
后面发现可以不用set来记录访问过的元素,只需要将访问过的元素值进行修改就可以实现记录的功能。
class Solution {
public:
int arrayNesting(vector<int>& nums) {
int len = nums.size();
int res = 0;
for(int i = 0; i < len; i++){
int cnt = 0;
int temp = i;
while(nums[temp] != -1){
cnt++;
int next = nums[temp];
nums[temp] = -1;
temp = next;
}
res = max(cnt, res);
}
return res;
}
};
运行速度:24ms。