LeetCode 287. Find the Duplicate Number

本文介绍了一种寻找数组中重复数字的高效算法。该算法利用原地哈希的思想,在不修改输入数组且仅使用常数额外空间的情况下,实现了O(n)的时间复杂度。文章提供了两种实现方法:一是通过标记数组元素的正负来识别重复项;二是运用置换思想,将每个元素交换到其应处的位置,最后检查未到位的元素即为重复。此外,还介绍了一个有趣的角度,即使用快慢指针的方法找到链表中的环起点,巧妙解决此问题。

原题链接在这里:https://leetcode.com/problems/find-the-duplicate-number/

题目:

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.

Example 1:

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

Example 2:

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

Note:

  1. You must not modify the array (assume the array is read only).
  2. You must use only constant, O(1) extra space.
  3. Your runtime complexity should be less than O(n2).
  4. There is only one duplicate number in the array, but it could be repeated more than once.

题解:

每次取 Math.abs(nums[i])为index, 然后跳到index上,如果这个数是正数,那么把它变成负数,如果是负数,说明之前已经有操作使其为负,就有重复,返回index. 有类似题目Find All Numbers Disappeared in an Array.

Time Complexity: O(n). Space: O(1).

AC Java:

 1 public class Solution {
 2     public int findDuplicate(int[] nums) {
 3         if(nums == null || nums.length == 0){
 4             throw new IllegalArgumentException("Invalid input array.");
 5         }
 6         
 7         for(int i = 0; i<nums.length; i++){
 8             int index = Math.abs(nums[i]);
 9             if(nums[index] > 0){
10                 nums[index] = -nums[index];
11             }else{
12                 return index;
13             }
14         }
15         
16         //出了loop还没有返回 那么说明是error
17         return -1;
18     }
19 }

也可以采用First Missing Positive中swap的方法,把nums[i] swap到 index = nums[i]的位置上. 

第二遍扫描时如果出现了i != nums[i]时,就是nums[i]是duplicate.

Time Complexity: O(nums.length). Space: O(1).

AC Java:

 1 class Solution {
 2     public int findDuplicate(int[] nums) {
 3         for(int i = 0; i<nums.length; i++){
 4             if(nums[i]>=0 && nums[i]<nums.length && nums[i]!=nums[nums[i]]){
 5                 swap(nums, i, nums[i]);
 6                 i--;
 7             }
 8         }
 9         
10         for(int i = 0; i<nums.length; i++){
11             if(nums[i] != i){
12                 return nums[i];
13             }
14         }
15         
16         return -1;
17     }
18     
19     private void swap(int [] nums, int i, int j){
20         int temp = nums[i];
21         nums[i] = nums[j];
22         nums[j] = temp;
23     }
24 }

居然能由此题联想到Linked List Cycle II也是厉害.

这里的duplicate number就是cycle的起点. 课通过快慢指针找到cycle的起点.

Note: 这里回置walker是回置到0. 而不是nums[0]. 因为接下来是跳动nums[runner], runner 是index. 

Time Complexity: O(n). Space: O(1).

AC Java:

 1 public class Solution {
 2     public int findDuplicate(int[] nums) {
 3         if(nums == null || nums.length == 0){
 4             throw new IllegalArgumentException("Invalid input array.");
 5         }
 6         
 7         //walker and runner can't start at the same point
 8         //or while loop condition walker != runner is never used
 9         //while loop is skipped.
10         int walker = nums[0];
11         int runner = nums[nums[0]]; 
12         while(walker != runner){
13             walker = nums[walker];
14             runner = nums[nums[runner]];
15         }
16         
17         walker = 0;
18         while(walker != runner){
19             walker = nums[walker];
20             runner = nums[runner];
21         }
22         
23         return walker;
24     }
25 }

类似First Missing Positive.

转载于:https://www.cnblogs.com/Dylan-Java-NYC/p/4881212.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值