【Leetcode】287. 寻找重复数

147 阅读2分钟

题目描述

在这里插入图片描述

// 287. 寻找重复数

// 给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n)
// ,可知至少存在一个重复的整数。

// 假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。

题解

// hashset法
// 这题基本上和【剑指offer】03.数组中重复的数字 是一模一样的,
// 用hashset一个个存元素,存不进就重复
// 
// 执行用时:20 ms, 在所有 Java 提交中击败了7.34%的用户
// 内存消耗:57.7 MB, 在所有 Java 提交中击败了5.06%的用户
class Solution {
    public int findDuplicate(int[] nums) {
		HashSet<Integer> set = new HashSet<>();
		for (int num : nums) {
			if (!set.add(num))
				return num;
		}
		return -1;
    }
}

// 排序法
// 排序之后找相邻的重复元素
// 
// 执行用时:40 ms, 在所有 Java 提交中击败了5.29%的用户
// 内存消耗:55.9 MB, 在所有 Java 提交中击败了5.06%的用户
class Solution {
    public int findDuplicate(int[] nums) {
		Arrays.sort(nums);
		for (int i = 0; i < nums.length - 1; i++) {
			if (nums[i] == nums[i + 1])
				return nums[i];
		}
		return -1;
    }
}
// 原地置换法
// 跟【剑指offer】03.数组中重复的数字 不一样的是,这里的数组是从1开始数到n
// 的,所以0索引对应元素11索引对应元素2。所以i索引对应元素nums[i] - 1,
// 我们定义i索引遍历nums,记遍历元素为nums[i],如果索引i不为nums[i]-1,
// 说明遍历值nums[i]不符合条件,将当前遍历值nums[i]和nums[i]-1索引遍历的
// nums[nums[i]-1]元素交换(如果nums[nums[i]-1]依然不等于nums[i],或者
// 依然nums[i]-1不等于i,继续循环交换),如果再交换过程中发现nums[nums[i]-1]
// 和nums[i]相等,直接返回nums[i]即可。如果nums[i]-1等于i成立了,
// 那么i右移,继续让i和nums[i]建立起【nums[i]-1 = i】的匹配关系。
// 
// 针对实例[1,3,4,2,2]有过程如下:
//  i 
// [1,3,4,2,2]  nums[i]-1 == i
//    i 
// [1,3,4,2,2]  nums[i]-1 != i >> swap(nums, i, nums[i] - 1)
//    i 
// [1,4,3,2,2]  nums[i]-1 != i >> swap(nums, i, nums[i] - 1)
//    i 
// [1,2,3,4,2]  nums[i]-1 != i >> swap(nums, i, nums[i] - 1)
// 
class Solution {
    public int findDuplicate(int[] nums) {
		int i = 0;
		while (i < nums.length) {
			if (nums[i] - 1 != i) {
				if (nums[i] == nums[nums[i] - 1])
					return nums[i];
				swap(nums, i, nums[i] - 1);
			}
			else {
				i++;
			}
		}
		return -1;
    }
	
	public void swap(int[] nums, int i, int j) {
		int temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}
}


// 双指针-快慢针
// 思路同【Leetcode】142. 环形链表 II 。
// 先用快慢针一个走一步一个走两步,找到在环内的交点,
// 然后其中一个点被重置回起点,两个指针一起一步一步移动,下一次交点就是环的
// 起点。
// 这道题执行用时怎么都降不下去,我也是没办法了。
// 
// 执行用时:6 ms, 在所有 Java 提交中击败了10.81%的用户
// 内存消耗:54.2 MB, 在所有 Java 提交中击败了6.59%的用户
class Solution {
    public int findDuplicate(int[] nums) {
		int slow = nums[0], fast = nums[0];
		fast = intersection(nums, slow, fast);
		while (slow != fast) {
			slow = nums[slow];
			fast = nums[fast];
		}
		return slow;
    }
	
	public int intersection(int[] nums, int slow, int fast) {
		slow = nums[slow];
		fast = nums[fast];
		fast = nums[fast];
		while (slow != fast) {
			slow = nums[slow];
			fast = nums[fast];
			fast = nums[fast];
		}
		return slow;
	}
}


// 简化一下:
// 执行用时:5 ms, 在所有 Java 提交中击败14.94%的用户
// 内存消耗:55.7 MB, 在所有 Java 提交中击败了5.06%的用户
class Solution {
    public int findDuplicate(int[] nums) {
		int slow = nums[0], fast = nums[0];
		slow = nums[slow];
		fast = nums[fast];
		fast = nums[fast];
		while (slow != fast) {
			slow = nums[slow];
			fast = nums[nums[fast]];
		}
		slow = nums[0];
		while (slow != fast) {
			slow = nums[slow];
			fast = nums[fast];
		}
		return slow;
    }
}