给定n个数字的数组,里面的值都是1-n,可是有的出现了两遍,所以有的没有出现,求没有出现值这个数组中的值有哪些。java
要求不能用额外的空间(除了返回列表以外),时间复杂度n数组
由于不能用额外空间而且时间是O(n),因此不能用排序或者hashapp
经过在对应位置的值去肯定下一个位置,一直到遍历完。其实本身也没有很成熟的思想。code
好比对于[4,3,2,7,8,2,3,1]
:
A[0],4===>找到a[3],7===>a[6],3===>a[2]======注意有可能出现循环,行不通。排序
原本觉得行不通,后来通过思考,能够行得通,只不过复杂度是O(k*n),k是重复的数字的个数,也是缺乏的数字的个数。思路是这样的A[0],4,而且把A[0]标记为-1===>a[3],7并把4放到a[3]===>a[6],3,把7放到a[6],===>a[2],2,把3放到a[2]===>a[1],3,把2放到a[3],===>想把3放到a[2],只是a[2]已经=3,因此3是数组中重复的。一个循环结束,从A[0]又开始,找到!=-1,而且!=i+1的a[i],把里面的值放到对应的位置上。一直到全部位置不是-1就是i+1结束。位置是-1的,对应空缺数值i+1。hash
public static List<Integer> findDisappearedNumbers(int[] nums) { List<Integer> result=new ArrayList<>(); boolean isEnding=false;//用isEnding检查是否全部位置不是-1就是i+1 boolean isExist=false;//是否从上一个位置取出了数字 int i=0;//表明找到的位置 while(!isEnding){ isEnding=true; i=0; while(i<nums.length){ if((nums[i]!=i+1)&&(nums[i]!=-1)){//没有重复,能够放进去 isEnding=false; int tmp=nums[i]; if(isExist){//若是有能够放进去的值,就先取出来再放进去 nums[i]=i+1; }else{//不然,只能取出来,并把-1放进去 nums[i]=-1; } i=tmp-1; isExist=true; }else{//若是相等,那么就重复了不须要放进去,直接往前面去;碰到了-1,若是须要放进去,就先放进去,再日后面去 if(isExist&&nums[i]==-1){ nums[i]=i+1; } i++; isExist=false; } } } for(i=0;i<nums.length;i++){ if(nums[i]==-1){ result.add(i+1); } } return result; }
看了看solution,是把全部的对应值的对应位置上的值都置为相反数:nums[|nums[i]| -1] = -|nums[|nums[i]|-1]|
,若是第二次遍历发现它>0,那么它是没见过的。好比[4,3,2,7,8,2,3,1]
,遍历一遍以后,获得[-4,-3,-2,-7,8,2,-3,-1]
,因此是八、2对应位置的数值没有在数组出现过,也就是5,6
io