LeetCode287之寻找重复数(相关话题:位运算,抽屉原理)

目录

题目描述

解法一:抽屉原理

思路一

思路二

解法二:位运算

解题总结


题目描述

给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次。找到所有出现两次的元素。你可以不用到任何额外空间并在O(n)时间复杂度内解决这个问题吗?

示例:

输入:
[4,3,2,7,8,2,3,1]

输出:
[2,3]

解法一:抽屉原理

思路一

仔细观察题目描述 1 ≤ a[i] ≤ n (n为数组长度),数组里的不同的元素类别可视为抽屉。数组个数视之为苹果

1.从头到位遍历数组如果发现 i==(a[i]-1),说明a[i]处的数据是对的,直接跳过。

2. i!=(a[i]-1)的话再判断a[a[i]-1]==a[i]是否成立,成立的话说明a[i]出现过2次,直接放入结果

3.a[a[i]-1]!=a[i]的话交换下标a[i]-1和i处的数据,交换之后可能导致a[i]-1>i,这时i可以不用继续向前移动,a[i]-1<=i的话要继续移动i

LeetCode287之寻找重复数(相关话题:位运算,抽屉原理)_第1张图片 结合具体示例理解上述算法描述
class Solution {
    public List findDuplicates(int[] nums) {

        List ans = new ArrayList();

        int n = nums.length;
        for( int i =0;i curVal-1 时,说明curVal-1索引处的值被处理过,这里直接交换
                // 当i

思路二

把下标index和下标nums[index]处的数位互换,数组重复或则之前已经有序的下标结束循环

​
class Solution {

    public int findDuplicate(int[] nums) {
        
        int index = 0;

        while(index < nums.length){

           if(nums[index]-1!= index){

        	   //这种情况构成循环所以要额外判断
               if(nums[index] == nums[nums[index]-1]){
                   return nums[index];
               }
               //index之前的下标已经有序,再次出现小于的元素可认为是重复
               if(nums[index]-1 < index){
                   return nums[index];
               }
  
               swap(nums,nums[index]-1,index);

           }else {
               index++;
           }

        }
       return 0;
   }

   private void swap(int[] nums,int i,int j){

       int tmep = nums[i];
       nums[i] = nums[j];
       nums[j] = tmep;
 
   }
}

​

解法二:位运算

 [1,n]的二进制中的各位是1的数次是固定的,比如

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

[1, 4]的位数如下

LeetCode287之寻找重复数(相关话题:位运算,抽屉原理)_第2张图片

从上面我们可以知道,如果第i位1的总数x > y,那么重复数的第i位就是1;

class Solution {
    public int findDuplicate(int[] nums) {
        int n = nums.length, ans = 0;
        int bit_max = 31;
        while (((n - 1) >> bit_max) == 0) {
            bit_max -= 1;
        }
        for (int bit = 0; bit <= bit_max; ++bit) {
            int x = 0, y = 0;
            for (int i = 0; i < n; ++i) {
                //把nums[1]-nums[n]的第bit位为1的挨个计算一遍
                if ((nums[i] & (1 << bit)) != 0) {
                    x += 1;
                }
                //把1-n的第bit位为1的挨个计算一遍
                if (i >= 1 && ((i & (1 << bit)) != 0)) {
                    y += 1;
                }
            }
            if (x > y) {
                ans |= 1 << bit;
            }
        }
        return ans;
    }
}

解题总结

掌握解题的思想之后代码只是实现思想的工具,前期需要大量储备各种思想

另外本题还有二分和快慢指针的求解方法

LeetCode287之寻找重复数(相关话题:二分查找,快慢指针)_leetcode寻找重复记录_数据与后端架构提升之路的博客-CSDN博客

相似题目

LeetCode645错误的集合 
(参考题解-理解透彻版)

LeetCode448找到所有数组中消失的数字

LeetCode442数组中重复的数据

你可能感兴趣的:(#,算法,算法)