zoukankan      html  css  js  c++  java
  • 剑指Offer面试题51(Java版):数组中反复的数字

    题目:在一个长度为n的数组里的全部数字都在0到n-1的范围内。

    数组中某些数字是反复的,但不知道有几个数字反复了。也不知道每一个数字反复的次数。请找出数组中随意一个反复的数字。

    比如假设输入长度为7的数组{2,3,1,0,2,5,3},那么相应的输出是反复的数字2或者3.

    解决问题的一个简单的方法是先把输入的数组排序。从排序的数组中找出反复的数字是件easy的事情,仅仅须要从头到尾扫描排序后的数组就能够了。排序一个长度为n的数组须要时间为O(nlogn)时间。

    还能够利用哈希表来解决问题。从头到尾按顺序扫描数组中的每一个数。每扫描到一个数字的时候,都能够用O(1)的时间来推断哈希表里是否已经包括了该数字。假设哈希表里没有这个数字。就把它增加到哈希表里。

    假设哈希表里已经存在该数字了,那么就找到一个反复的数字。

    这个算法的时间复杂度为O(n),但它提高了时间复杂度是一个大小为O(n)的哈希表为代价的。我们再看看有没有时间复杂度为O(1)的算法。

    我们注意到数组中的数字都在0到n-1的范围内的。假设这个数组中没有反复的数字。那么当数组排序后数字i将出如今下标为i的位置。因为数组中有反复的数字。有些位置可能存在数字,同一时候有些位置可能没有数字。

    如今让我们重排这个数组。

    从头到尾稻苗这个数组中的每一个数字。当扫描到下标为i的数字的时候。首先比較这个数字(用m表示)是不是i。假设是,接着扫描下一个数字。

    假设不是,再拿它和第m个数字进行比較。

    假设它和第m个数字相等。就找到一个反复的数字(该数字在下标为i和m的位置都出现了)。假设它和第m个数字不想等,就把第i个数字和第m个数字交换,把m放到属于它的位置。接下来再反复这个比較。交换的过程。直到发现一个反复的数字。

    以数组{2,3,1,0,2,5,3}为例来分析找到反复数字的步骤。

    数组的第0个数字(从0開始计数,和数组的下标保持一致)是2,与它的下标不想等,于是把它和下标为2的数字1交换。交换后的数组是{1,3,2,0,2,5,3}。此时第0 个数字是1,仍然与它的下标不想等,继续把它和下标为1的数字3交换,得到数组{0。1。2。3,2,5,3}。此时第0 个数字为0。接着扫描下一个数字,在接下来的几个数字中。下标为1。2。3的三个数字分别为1。2,3,他们的下标和数值都分别相等,因此不须要做不论什么操作。接下来扫描下标为4的数字2.因为它的值与它的下标不登,再比較它和下标为2的数字。

    注意到此时数组中下标为2的数字也是2,也就是数字2和下标为2和下标4的两个位置了,因此找到一个反复的数字。

    Java代码实现例如以下:

    /**
     * 数组中反复的数字
     */
    package swordForOffer;
    
    /**
     * @author JInShuangQi
     *
     * 2015年8月12日
     */
    public class E51DuplicationInArray {
    	
    	public boolean duplicate(int[] arr){
    		if(arr== null || arr.length <= 0){
    			return false;
    		}
    		for(int i = 0;i<arr.length;i++){
    			if(arr[i] < 0 || arr[i] > arr.length-1)
    				return false;
    		}
    		for(int i = 0;i<arr.length;i++){
    			while(arr[i] != i){
    				if(arr[i] == arr[arr[i]]){
    					System.out.println(arr[i]);
    					return true;
    				}
    				else{
    					int temp = arr[i];
    					arr[i] = arr[temp];
    					arr[temp] = temp;
    				}
    			}
    		}
    		return false;
    	}
    	public static void main(String[] args){
    		int[] arr = {2,3,1,0,2,5,3};
    		E51DuplicationInArray test = new E51DuplicationInArray();
    		System.out.println(test.duplicate(arr));
    	}
    }
    

    . 在代码中虽然有一两个反复现年换。但每一个数字最多仅仅要交换两次就能找到属于自己的位置,因此总的时间复杂度为O(n),另外,全部的操作步骤都是在输入数组上进行。不须要额外的分配内存。因此空间复杂度为O(1).


  • 相关阅读:
    写时复制集合 —— CopyOnWriteArrayList 源码原理阅读笔记
    初步整合vue-element-admin和GitDataV两个Vue开源框架方案实现大数据可视化
    IOS苹果登录sign in with apple后端校验
    IOS审核被拒:IOS苹果授权登录(Sign in with Apple)/Apple登录/苹果登录集成教程
    ios安装自定义基座失败问题
    IOS APP上架App Store及提交审核详细教程
    IOS APP报错:SyntaxError: Invalid regular expression: invalid group specifier name __ERROR
    Apple Pay苹果支付IOS in-App Purchase内购项目服务端校验
    浅析浏览器是如何工作的(一):V8引擎、JIT机制、JS代码解释执行与编译执行
    ApplePay苹果支付内购项目配置及代码实现及沙箱测试
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6801180.html
Copyright © 2011-2022 走看看