数组中重复的数

数组中任意一个重复的数

1-题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字

例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

思路

1.交换
0~n-1正常的排序应该是A[i]=i;因此可以通过交换的方式,将它们都各自放回属于自己的位置;
从头到尾扫描数组A,当扫描到下标为i的数字m时,首先比较这个数字m是不是等于i,
如果是,则继续扫描下一个数字;
如果不是,则判断它和A[m]是否相等,如果是,则找到了第一个重复的数字(在下标为i和m的位置都出现了m);如果不是,则把A[i]和A[m]交换,即把m放回属于它的位置;
重复上述过程,直至找到一个重复的数字;
时间复杂度:O(n),空间复杂度:O(1)—所有的操作步骤都是在输入数组上进行的,不需要额外分配空间
(将每个数字放到属于自己的位置最多交换两次)

public class Solution {

    public boolean duplicate(int numbers[],int length,int [] duplication) {
       if(numbers==null||numbers.length<=0){
            duplication[0]=-1;
            return false;
        }
        for(int i=0;i<length;i++){
            if(numbers[i]<0||numbers[i]>length-1){
                duplication[0]=-1;
                return false;
            }
        }
        for(int j=0;j<length;j++){
            while(numbers[j]!=j){
                if(numbers[j]==numbers[numbers[j]]){
                    duplication[0]=numbers[j];
                    return true;
                }else{
                    int temp=numbers[j];
                    numbers[j]=numbers[temp];
                    numbers[temp]=temp;
                }
            }
        }
        duplication[0]=-1;
        return false;
    } 
  }

2.不需要额外的数组或者hash table来保存,题目里写了数组里数字的范围保证在0 ~ n-1 之间,所以可以利用现有数组设置标志,当一个数字被访问过后,可以设置对应位上的数 + n,之后再遇到相同的数时,会发现对应位上的数已经大于等于n了,那么直接返回这个数即可。
时间复杂度:O(n),空间复杂度:O(1)

 bool duplicate(int numbers[], int length, int []duplication) {
        for (int i = 0; i < length; ++i)
        {
            int index=numbers[i];
            if(index>=length)
                index-=length;
            if(numbers[index]>=length)
            {
                duplication[0]=index;
                return true;
            }
            numbers[index]=numbers[index]+length;
        }
         duplication[0]=-1;
        return false;
    }
2-题目描述(不修改数组)

在一个长度为n+1的数组里的所有数字都在1到n的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。
也不知道每个数字重复几次。请找出数组中任意一个重复的数字,但不能修改输入的数组。 例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7}, 那么对应的输出重复的数字2或者3。

思路

我们把从 1~n的数字从中间的数字m分为两部分, 后面半为m+1~n。
如果1~m的数字的数目超过m,那么这一半的区间里一定包含重复的数字:
否则,另一半m+1~n的区间里定包含重复的数字。我们可以继续把包含重复数字的区间一分为二, 直到找到一个重复的
数目。
二分法

   public static boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null||numbers.length<=0){
            duplication[0]=-1;
            return false;
        }
        for(int i=0;i<length;i++){
            if(numbers[i]<1||numbers[i]>length-1){
                duplication[0]=-1;
                return false;
            }
        }
        int low=1;
        int high=length-1;
        while(low<=high){
            int mid=(high+low)/2;
            int count=CountRange(numbers,length,low,mid);
            if(low==high){
                if(count>1){
                    duplication[0]=low;
                    return true;
                }else{
                    break;
                }
            }else{
                if(count>mid-low+1){
                    high=mid;
                }else{
                    low=mid+1;
                }
            }
        }
        duplication[0]=-1;
        return false;
    }
    public static int CountRange(int numbers[],int length,int min,int max) {
        int count=0;
        for(int i=0;i<length;i++){
            if(numbers[i]>=min&&numbers[i]<=max){
                count++;
            }
        }
        return count;
    }

数组中所有重复的数及次数

1-题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中所有重复的数字及其次数

例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出2,2。前面是重复元素,后边是次数

思路
import java.util.HashMap;  
import java.util.Set;      
public class Solution {

   public static void duplicate(int numbers[],int length,int [] duplication) {
        if(numbers==null||numbers.length<=0){
            duplication[0]=-1;
        }
        for(int i=0;i<numbers.length;i++){
            if(numbers[i]<0||numbers[i]>=numbers.length){
                duplication[0]=-1;
            }
        }
        HashMap <Integer, Integer>map = new HashMap<Integer, Integer>();
        //hash映射
        for (int i = 0; i < length; i++) {
            if (map.containsKey(numbers[i])) {
                int temp = map.get(numbers[i]);
                map.put(numbers[i], ++temp);
            } else
                map.put(numbers[i], 1);
        }
        //找到第一个重复的 return
        Set<Integer> set = map.keySet();
        for(int i : set) {
            if (map.get(i) >= 2 ) {
                duplication[i] = i;
                System.out.print("重复数字:"+i);
                System.out.print("重复次数:"+map.get(i));
                System.out.println("");
            }
        }
    }

题目2----检查链表是否有环

环检测算法(Floyd’s Tortoise and Hare)
  • 分析:当兔子和乌龟在环形跑道上跑步时,在某一时刻,兔子会追上乌龟

  • 两个步骤,第一个步骤是确定链表是否有环(也就是重复的数字),第二个步骤是确定环的入口点(重复的数字)在哪里。

    1.首先,我们初始化两个指针,一个快速的 hare 指针,一个慢的Tortoise 指针。让hare 一次走两个节点,Tortoise 一个节点。最终,Tortoise 和hare 总会在相同的节点相遇,这样就可以证明是否有环。
    2.我们初始化两个指针:ptr1指向列表头部的指针,指向ptr2交叉点的指针 。然后,我们把他们每个每次前进1个节点,直到他们相遇; 他们相遇的节点是环的入口,我们就可以得出结果。

  • 时间复杂度O(n)空间复杂度O(1)

 public int findDuplicate(int[] nums) {
        // Find the intersection point of the two runners.
        int tortoise = nums[0];
        int hare = nums[0];
        do {
            tortoise = nums[tortoise];
            hare = nums[nums[hare]];
        } while (tortoise != hare);

        // Find the "entrance" to the cycle.
        int ptr1 = nums[0];
        int ptr2 = tortoise;
        while (ptr1 != ptr2) {
            ptr1 = nums[ptr1];
            ptr2 = nums[ptr2];
        }
        return ptr1;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值