leetcode刷题记录之287

287、寻找重复数

  给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:

输入: [1,3,4,2,2]
输出: 2

示例 2:

输入: [3,1,3,4,2]
输出: 3

说明:

  1. 不能更改原数组(假设数组是只读的)。
  2. 只能使用额外的 O(1) 的空间。
  3. 时间复杂度小于 O(n2) 。
  4. 数组中只有一个重复的数字,但它可能不止重复出现一次。

难度:中等  题目地址:https://leetcode-cn.com/problems/find-the-duplicate-number/

1、C语言代码:
//解法一:暴力法
int findDuplicate(int* nums, int numsSize){
    for(int i = 0;i < numsSize - 1;i++){
        for(int j = i + 1;j < numsSize;j++){
            if(nums[i] == nums[j])
                return nums[i];
        }
    }
    return;
}
//解法二:排序法
int cmp(const void *a, const void *b){
    return (*(int *)a - *(int *)b);
}
int findDuplicate(int* nums, int numsSize){
    qsort(nums, numsSize, sizeof(int), cmp);
    for (int i = 0; i < numsSize - 1; i++) {
        if (nums[i] == nums[i + 1]) {
            return nums[i];
        }
    }
    return;    
}

解释: 方法一暴力求解,双重循环判断是否有重复数。
方法二:如果对数字进行排序,则任何重复的数字都将与排序后的数组相邻。

知识点回顾: 无。

2、Java代码:
//解法一:集合
class Solution {
    public int findDuplicate(int[] nums) {
        Set<Integer> seen = new HashSet<Integer>();
        for (int num : nums) {
            if (seen.contains(num)) {
                return num;
            }
            seen.add(num);
        }
        return -1;
    }
}
//解法二:快慢指针法
class Solution {
    public int findDuplicate(int[] nums) {
        int length = nums.length;
        if (length > 1) {
            // 找到快慢指针相遇的地方
            int slow = nums[0];
            int fast = nums[nums[0]];
            while (fast != slow) {
                slow = nums[slow];
                fast = nums[nums[fast]];
            }
            // 用一个新指针从头开始,直到和慢指针相遇
            fast = 0;
            while (fast != slow) {
                slow = nums[slow];
                fast = nums[fast];
            }
            return slow;
        }
        return -1;
    }
}

解释: 方法一:如果我们在数组上迭代时存储每个元素,我们可以在数组上迭代时简单地检查每个元素。为了实现线性时间复杂性,我们需要能够在恒定时间内将元素插入数据结构(并查找它们)。set 很好地满足这些约束,所以我们迭代数组并将每个元素插入 seen 中。在插入之前,我们检查它是否已经存在。如果是,那么我们找到了我们的副本,所以我们返回它。
方法二:假设数组中没有重复,那我们可以做到这么一点,就是将数组的下标和1到n每一个数一对一的映射起来。比如数组是213,则映射关系为0->2, 1->1, 2->3。假设这个一对一映射关系是一个函数f(n),其中n是下标,f(n)是映射到的数。如果我们从下标为0出发,根据这个函数计算出一个值,以这个值为新的下标,再用这个函数计算,以此类推,直到下标超界。实际上可以产生一个类似链表一样的序列。比如在这个例子中有两个下标的序列,0->2->3。
但如果有重复的话,这中间就会产生多对一的映射,比如数组2131,则映射关系为0->2, {1,3}->1, 2->3。这样,我们推演的序列就一定会有环路了,这里下标的序列是0->2->3->1->1->1->1->…,而环的起点就是重复的数。
所以该题实际上就是找环路起点的题。过程是这样的:我们先用快慢两个下标都从0开始,快下标每轮映射两次,慢下标每轮映射一次,直到两个下标再次相同。这时候保持慢下标位置不变,再用一个新的下标从0开始,这两个下标都继续每轮映射一次,当这两个下标相遇时,就是环的起点,也就是重复的数。

知识点回顾: 无。

3、Python代码:
class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        return int(abs(sum(nums)-sum(set(nums)))/abs(len(nums)-len(set(nums))))

解释: 重复数字是原始数组和求集合后的差值除以长度差。

知识点回顾: 无。

4、JavaScript代码:
/**
 * @param {number[]} nums
 * @return {number}
 */
var findDuplicate = function(nums) {
    for(let i = 0;i < nums.length;i++){
      if(nums.indexOf(nums[i]) !== nums.lastIndexOf(nums[i])){
          return nums[i]
      } 
    } 
};

解释: 直接判断。

知识点回顾:
1、indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
如果没有找到匹配的字符串则返回 -1。
注意: indexOf() 方法区分大小写。
语法:string.indexOf(searchvalue,start)
searchvalue:必需。规定需检索的字符串值。
start:可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 string Object.length - 1。如省略该参数,则将从字符串的首字符开始检索。
返回值:查找指定字符串第一次出现的位置,如果没找到匹配的字符串则返回  -1。
2、lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置,如果指定第二个参数 start,则在一个字符串中的指定位置从后向前搜索。
注意: 该方法将从后向前检索字符串,但返回是从起始位置 (0) 开始计算子字符串最后出现的位置。 看它是否含有字符串。开始检索的位置在字符串的 start 处或字符串的结尾(没有指定 start 时)。
如果没有找到匹配字符串则返回  -1 。
注意:lastIndexOf() 方法是区分大小写的!
语法:string.lastIndexOf(searchvalue,start)
searchvalue:必需。规定需检索的字符串值。
start:可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的最后一个字符处开始检索。
返回值:查找的字符串最后出现的位置,如果没有找到匹配字符串则返回  -1。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值