• [LeetCode] 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.

    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:

    1. N is an integer within the range [1, 20,000].
    2. The elements of A are all distinct.
    3. Each element of A is an integer within the range [0, N-1].

    这道题让我们找嵌套数组的最大个数,给的数组总共有n个数字,范围均在 [0, n-1] 之间,题目中也把嵌套数组的生成解释的很清楚了,其实就是值变成坐标,得到的数值再变坐标。那么实际上当循环出现的时候,嵌套数组的长度也不能再增加了,而出现的这个相同的数一定是嵌套数组的首元素,博主刚开始没有想清楚这一点,以为出现重复数字的地方可能是嵌套数组中间的某个位置,于是用个 set 将生成的嵌套数组存入,然后每次查找新生成的数组是否已经存在。而且还以原数组中每个数字当作嵌套数组的起始数字都算一遍,结果当然是 TLE 了。其实对于遍历过的数字,我们不用再将其当作开头来计算了,而是只对于未遍历过的数字当作嵌套数组的开头数字,不过在进行嵌套运算的时候,并不考虑中间的数字是否已经访问过,而是只要找到和起始位置相同的数字位置,然后更新结果 res,参见代码如下:

    解法一:

    class Solution {
    public:
        int arrayNesting(vector<int>& nums) {
            int n = nums.size(), res = INT_MIN;
            vector<bool> visited(n, false);
            for (int i = 0; i < nums.size(); ++i) {
                if (visited[nums[i]]) continue;
                res = max(res, helper(nums, i, visited));
            }
            return res;
        }
        int helper(vector<int>& nums, int start, vector<bool>& visited) {
            int i = start, cnt = 0;
            while (cnt == 0 || i != start) {
                visited[i] = true;
                i = nums[i];
                ++cnt;
            }
            return cnt;
        }
    };

    下面这种方法写法上更简洁一些,思路完全一样,参见代码如下:

    解法二:

    class Solution {
    public:
        int arrayNesting(vector<int>& nums) {
            int n = nums.size(), res = INT_MIN;
            vector<bool> visited(n, false);
            for (int i = 0; i < n; ++i) {
                if (visited[nums[i]]) continue;
                int cnt = 0, j = i;
                while(cnt == 0 || j != i) {
                    visited[j] = true;
                    j = nums[j];
                    ++cnt;
                }
                res = max(res, cnt);
            }
            return res;
        }
    };

    下面这种解法是网友 @edyyy 提醒博主的,可以优化解法二的空间,我们并不需要专门的数组来记录数组是否被遍历过,而是在遍历的过程中,将其交换到其应该出现的位置上,因为如果某个数出现在正确的位置上,那么它一定无法组成嵌套数组,这样就相当于我们标记了其已经访问过了,思路确实很赞啊,参见代码如下:

    解法三:

    class Solution {
    public:
        int arrayNesting(vector<int>& nums) {
            int n = nums.size(), res = 0;
            for (int i = 0; i < n; ++i) {
                int cnt = 1;
                while (nums[i] != i) {
                    swap(nums[i], nums[nums[i]]);
                    ++cnt;
                }
                res = max(res, cnt);
            }
            return res;
        }
    };

    Github 同步地址:

    https://github.com/grandyang/leetcode/issues/565

    类似题目:

    Nested List Weight Sum II

    Flatten Nested List Iterator 

    Nested List Weight Sum

    参考资料:

    https://leetcode.com/problems/array-nesting/

    https://leetcode.com/problems/array-nesting/discuss/102432/C%2B%2B-Java-Clean-Code-O(N)

    https://leetcode.com/problems/array-nesting/discuss/232283/C%2B%2B-straightforward-solution-beats-100

    LeetCode All in One 题目讲解汇总(持续更新中...)

  • 相关阅读:
    DevExpress 学习链接
    DevExpress TreeList用法总结
    DevExpress 用户控件 分页(中)
    DevExpress通过girdcontrol实现分页
    DevExpress 操作gridcontrol
    通过c#操作word文档的其他方式
    DocX操作word生成报表
    数学文化 剩余定理
    数学文化 卢卡斯数列和黄金分割
    mac 终端高亮显示~
  • 原文地址:https://www.cnblogs.com/grandyang/p/6932727.html
Copyright © 2020-2023  润新知