zoukankan      html  css  js  c++  java
  • [LeetCode] 287. Find the Duplicate Number(寻找重复数字)

    Description

    Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.
    给定一个包含 n + 1 个范围在 [1, n] 的整数的整数数组 nums

    There is only one duplicate number in nums, return this duplicate number.
    数组里只存在一个重复的数字,找出这个重复的数字。

    Follow up

    1. How can we prove that at least one duplicate number must exists in nums?
      如何证明 nums 内一定存在至少 1 个重复的数字?

    2. Can you solve the problem without modifying the array nums ?
      你能在不修改 nums 的情况下解答此问题吗?

    3. Can you solve the problem using only constant, O(1) extra space?
      你能在 (O(1)) 空间复杂度内解答此问题吗?

    4. Can you solve the problem with runtime complexity less than O(n^2)?
      你能在小于 (O(N^2)) 时间复杂度内解答此问题吗?

    Examples

    Example 1

    Input: nums = [1,3,4,2,2]
    Output: 2
    

    Example 2

    Input: nums = [3,1,3,4,2]
    Output: 3
    

    Example 3

    Input: nums = [1,1]
    Output: 1
    

    Example 4

    Input: nums = [1,1,2]
    Output: 1
    

    Constraints

    • 2 <= n <= 3*10^4

    • nums.length == n + 1

    • 1 <= nums[i] <= n

    • All the integers in nums appear only once except for precisely one integer which appears two or more times

    Solution

    感觉所有 Follow-up 里最好做到的是第 4 点,下面给出一个一般人都会想到的常规解法,时间复杂度 (O(N)),空间复杂度 (O(N)),不修改原数组:

    class Solution {
        fun findDuplicate(nums: IntArray): Int {
            return nums.freq()
                .filter { it.value > 1 }
                .map { it.key }
                .first()
        }
    
        private fun IntArray.freq(): Map<Int, Int> {
            val result = hashMapOf<Int, Int>()
            this.forEach { result[it] = result.getOrDefault(it, 0) + 1 }
            return result
        }
    }
    

    一开始看到这问题的时候,我首先想到的是之前做过的第 448 题. Find All Numbers Disappeared in an Array,但只是觉得有点像,但思路似乎不能通用,看了一眼 discussion 后茅塞顿开。要解答这个问题,我们不妨按以下规则遍历一遍数组:

    1. 起始状态是 nums[0]

    2. 以前一个数作为下标,取出 nums[prev] 作为下一个数。

    因为题目规定数组长度是 n + 1,所有数的范围是 [1, n],所以不用担心数组越界,将样例中的四个数组按如上方法遍历,得到以下结果:

    [1,3,4,2,2] =>
        1 -> 3 -> 2 -> 4 -> 2 -> 4 -> 2 -> 4 -> ...
    [3,1,3,4,2] =>
        3 -> 4 -> 2 -> 3 -> 4 -> 2 -> 3 -> 4 -> 2 -> ...
    [1,1] =>
        1 -> 1 -> 1 -> ...
    [1,1,2] ->
        1 -> 1 -> 1 -> ...
    

    这不是成环链表遍历之后的形式吗?成环的那个节点即为所求。于是答案呼之欲出:参考成环链表找环的方法,无需修改原数组,时间复杂度 (O(N)),空间复杂度 (O(1))

    class Solution {
        fun findDuplicate(nums: IntArray): Int {
            // head = nums[0]
            // fast = head.next.next
            var fast = nums[nums[nums[0]]]
            // slow = head.next
            var slow = nums[nums[0]]
    
            while (fast != slow) {
                fast = nums[nums[fast]]
                slow = nums[slow]
            }
    
            // 二者相遇,fast 移动回起点
            fast = nums[0]
            while (fast != slow) {
                fast = nums[fast]
                slow = nums[slow]
            }
    
            return slow
        }
    }
    
  • 相关阅读:
    MySQL-第十四篇事务管理
    MySQL-第十三篇使用ResultSetMetaData分析结果集
    MySQL-第十二篇管理结果集
    MySQL-第十一篇JDBC典型用法
    MySQL-第十篇多表连接查询
    Java中List集合去除重复数据的方法1
    去除List集合中的重复值(四种好用的方法)(基本数据类型可用)
    去除list集合中重复项的几种方法
    Java中List集合去除重复数据的四种方法
    Java中List集合去除重复数据的方法
  • 原文地址:https://www.cnblogs.com/zhongju/p/13935352.html
Copyright © 2011-2022 走看看