leetcode-每日一题565. 数组嵌套(标记图和并查集)

leetcode-每日一题565. 数组嵌套(标记图和并查集)_第1张图片
题目链接:https://leetcode.cn/problems/array-nesting/

思路

方法一、并查集

直接想法
这题告诉我们数组内的数字是0-N-1,且不会重复,我们可以把A[i] , A[A[i]]…看成一个环,数组可以被分成多个环,我们只需计算多个环中的最大长度即可
判断环这里我们用的并查集,把每个元素看成一棵树,将同一个环的A[i] 和A[A[i]]两棵树合并,怎么判断他是同一个环呢?我们只需要去递归走下去,走到他的根节点,判断他们的根节点是否相同即可

算法

  1. 初始化f数组和size数组,f数组记录当前结点的根节点,初始化都是以自己为根节点,size数组记录每个树的大小
  2. find函数用来找当前nums[i]的根节点
  3. merge函数用来合并同一环的子树,如果我们同根了表示已经合并过了则直接退出
  4. 循环遍历nums数组,合并nums[i]和nums[nums[i]]两棵树

代码示例

func arrayNesting(nums []int) int {
    f := make([]int, len(nums))
    size := make([]int, len(nums))
    for i := range f{
        f[i] = i
        size[i] = 1
    }
    ans := 1
    var find func(x int) int
    find = func(x int) int{
        if x == f[x]{
            return x
        }
        return find(f[x])
    }
    merge := func(x, y int){
        a := find(x)
        b := find(y)
        if a == b{
            return
        }
        f[b] = f[a]
        size[a] += size[b]
        if ans < size[a]{
            ans = size[a]
        }
    }
    for i := range nums{
        merge(nums[i], nums[nums[i]])
    }
    return ans
}

leetcode-每日一题565. 数组嵌套(标记图和并查集)_第2张图片

复杂度分析

  • 时间复杂度:O(n) 其中n表示nums数组的长度,遍历一次nums数组需要O(n)的时间
  • 空间复杂度:O(2 * n) 其中n表示nums数组的长度,需要申请f数组和size数组的空间

方法二、标记图

直接想法
遍历数组,从 i 向 nums[i] 连边,我们可以得到一张有向图。

由于题目保证nums 中不含有重复的元素,因此有向图中每个点的出度和入度均为 1。

在这种情况下,有向图必然由一个或多个环组成。我们可以遍历 nums,找到节点个数最大的环。

利用nums 中的元素大小在 [0, n-1] 之间这一条件,我们可以省略 vis 数组,改为标记 nums[i]=n,来实现和 vis 数组同样的功能。

代码示例

func arrayNesting(nums []int) (ans int) {
    n := len(nums)
    for i := range nums {
        cnt := 0
        for nums[i] < n {
            i, nums[i] = nums[i], n
            cnt++
        }
        if cnt > ans {
            ans = cnt
        }
    }
    return
}

leetcode-每日一题565. 数组嵌套(标记图和并查集)_第3张图片

复杂度分析

  • 时间复杂度:O(n),其中 nn 是数组 nums 的长度。

  • 空间复杂度:O(1),我们只需要常数的空间保存若干变量。

你可能感兴趣的:(leetcode算法实战,leetcode,算法,职场和发展,go,学习)