565 Array Nesting

题目

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值