循环排序1.找到数组中重复数字

本文探讨了如何在数组中找到重复的数字。当数组大小为n+1且数字范围为[1,n]时,通过排序和哈希表的方法可以找到重复的值。此外,还讨论了在不允许更改数组的情况下,如何利用partition算法来解决问题。对于寻找所有重复的元素,可以通过循环排序方法找到不在正确位置的元素,这些即为重复元素。" 116303876,10914725,Python编程:猴子吃桃问题与闰年判断,"['Python', '算法', '递归算法', '数学问题', '编程练习']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

找出数组中一个重复的数字

数组大小为n+1,数组中数字大小为[1,n],只有一个重复

分析这个题发现有n+1个整数,数组下标在[0,n],数字大小在[1,n],也就是数组中最起码有一个重复的数,假设只有一个重复的值(记住这种时候比的是数组,下标用num[i]-1记录)
(1)在一个排序好的数组中找到重复的数字非常容易,排序的时间复杂度是O(nlogn)。
(2)然后也可以利用哈希表来解决这个问题,扫描到一个数字时利用O(1)的复杂度来看是否哈希表中中已经包含了该数字,这样的话只要遍历一遍就可以得到,但这样是以一个空间复杂度为O(n)的哈希表来为代价的。也就是遍历数组,并建立一个boolean数组记录这个数字是否遍历过(这里使用的最大原因是数组的内容长度在0到n-1范围内,否则可以利用一个map来记录),找到返回即可。
(3)所以最好想一个空间复杂度为O(1)也就是不用额外分配空间的算法。因为数组在1到n的范围内,所以如果没有重复,大小为i的数字排序好会出现在i-1的位置上,而且数字0是不会出现的,循环数组进行数组遍历,这个题肯定不会缺失数,所以比较i和arr[i]-1是否相等,相等则i++,不相等则交换arr[i]和arr[arr[i]],在交换之前要看会出现这两个值相等的情况,只要出现说明这个数字就是那个重复的数字。时间复杂度为O(n)。空间复杂度为O(1)。
(4)如果数组不允许更改,则使用partition算法。

class Solution {
    public int findDuplicate(int[] nums) {
        if(nums==null || nums.length==0) return 0;
        int i=0;
        int n=nums.length;
        while(i<n){
            int x=nums[i]-1;
            if(x!=i){
                if(nums[x]==nums[i]) return nums[i];
                else{
                    nums[i]=nums[x];
                     nums[x]=x+1; 
                }
            }else{
                i++;
            }
        }
       
        return n;
    }
(4)如果不能修改数组,则可以使用partition思想来做

长度为n,数字在[0,n-1]中。不知道有几个重复了,求输出任意一个重复的数字。

分析可知这个数组的下标为[0,n-1],数字大小也为[0,n-1],所以如果没有重复,数字arr[i]会等于i。他现在是不知道有几个重复的值,随便输出一个就行。循环数组,此时可能会有缺的值,也可能会有重复值,所以在遍历过程中先判断i是否等于arr[i],若等于则i++,若不等于则再判断arr[i]和arr[arr[i]],不等于则要交换arr[i]和arr[arr[i]],如果相等则这两个值就是重复的值,输出即可。

class Solution {
    public int findRepeatNumber(int[] nums) {
          if(nums==null || nums.length==0) return -1;
          int i=0;
          int n=nums.length;
          while(i<n){
              int x=nums[i];
              if(x!=i){
                  if(x==nums[x]){
                    return x;
                  }else{
                     nums[i]=nums[x];
                     nums[x]=x;
                  }
              }else{
                  i++;
              } 
          }
          return -1;
    }
}
如果要求输出第一个(牛客网)

这样会打乱求的顺序,所以应该换一种做法,比如说用哈希表

    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null || numbers.length==0) return false;
          boolean[] hash=new boolean[length];
          for(int i=0;i<length;i++){
              if(hash[numbers[i]]==false){
                  hash[numbers[i]]=true;
              }else{
                  duplication[0]=numbers[i];
                  return true;
              }
          }
          return false;
    }

数组长度为n,元素为[1,n],有些元素出现一次有些元素出现两次。要找到所有的出现两次的元素。要求不用空间复杂度。

分析可知这个题无序数组,数组大小有限,下标为[0,n-1],而元素为1到n,所以如果所有元素出现1次就是下标为i的元素为i+1.现在不是这样,那利用循环排序来排好,这样各个元素都会在自己的位子上,不在自己位子上的就是多出来的。

import java.util.ArrayList;
class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> res=new ArrayList<Integer>();
        if(nums==null || nums.length==0)return res;
        int i=0;
        int n=nums.length;
        while(i<n){
            int x=nums[i]-1;
            if(x!=i && nums[i]!=nums[x]){
                nums[i]=nums[x];
                nums[x]=x+1;
            }else{
                i++;
            }
        }
        for(int j=0;j<n;j++){
            if(nums[j]!=j+1){
                res.add(nums[j]);
            }
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值