[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 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM