题目
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.
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}
想法
Time Limit Exceeded Solution 这个就是暴力搜索,提交显示测试用例超时,853/856通过
Accept Solution 在暴力搜索的基础上,简化,分析问题如下:
i= 0 : 5 6 2 0 5 ->4
i= 1 : 4 1 4 ->2
i= 2 : 0 5 6 2 0 ->4
i= 3 : 3 3
i= 4 : 1 4 1
…
分析如下,凡是已经出现在搜索过的值,便不用在搜索,最大值是相同的
结果只是求出最大值即可。
MyCode
Time Limit Exceeded Solution
class Solution {
public int arrayNesting(int[] nums) {
int [] tp_lon = new int[nums.length];
for ( int i = 0;i< nums.length;i++){
tp_lon[nums[i]] = findLon( nums , i);
}
Arrays.sort( tp_lon );
return tp_lon[tp_lon.length-1];
}
int findLon( int[] nums,int i ){
Set set=new HashSet();
Boolean tp_bl = Boolean.FALSE;
int tp = nums[i];
while( !tp_bl){
set.add( tp ) ;
tp = nums[tp];
tp_bl = set.contains(tp);
}
return set.size();
}
}
Accept Solution
class Solution {
public int arrayNesting(int[] nums) {
int [] tp_lon = new int[nums.length];
int [] map = new int[nums.length];
for ( int i = 0;i< nums.length;i++){
tp_lon[nums[i]] = findLon( map , nums , i);
}
Arrays.sort( tp_lon );
return tp_lon[tp_lon.length-1];
}
int findLon( int [] map ,int[] nums,int i ){
Set set=new HashSet();
Boolean tp_bl = Boolean.FALSE;
int tp = nums[i];
if( map[tp] > 0)
return 0;
while( !tp_bl){
set.add( tp ) ;
map[tp] = 1;
tp = nums[tp];
tp_bl = set.contains(tp);
}
return set.size();
}
}
Other Classic Solution
solution one
思路和我的Accepted代码完全一致,但是这个算法更加精简,因为只要最大值,便不用数组记录,而是用变量只记录最大值,节省空间
而且没有使用set记录路径,因为分析可得,只要路径中和开始相同就会结束,因此只记录是否和开始元素相同即可,一般没有递归不用引入子函数
public class Solution {
public int arrayNesting(int[] nums) {
boolean[] visited = new boolean[nums.length];
int res = 0;
for (int i = 0; i < nums.length; i++) {
if (!visited[i]) {
int start = nums[i], count = 0;
do {
start = nums[start];
count++;
visited[start] = true;
}
while (start != nums[i]);
res = Math.max(res, count);
}
}
return res;
}
}
Best solution
In the last approach, the visitedvisited array is used just to keep a track of the elements of the array which have already been visited. Instead of making use of a separate array to keep track of the same, we can mark the visited elements in the original array numsnums itself. Since, the range of the elements can only be between 1 to 20,000, we can put a very large integer value Integer.MAX_VALUE at the position which has been visited. The rest process of traversals remains the same as in the last approach.
不使用多余的访问数组,一旦某个元素被范访问过,那么原始数组中存储的数值便失去意义,可以用来记录是否已经访问。
public class Solution {
public int arrayNesting(int[] nums) {
int res = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != Integer.MAX_VALUE) {
int start = nums[i], count = 0;
while (nums[start] != Integer.MAX_VALUE) {
int temp = start;
start = nums[start];
count++;
nums[temp] = Integer.MAX_VALUE;
}
res = Math.max(res, count);
}
}
return res;
}
}