求一个数组中没有出现的最小正数,要求时间复杂度O(n),空间复杂度O(1)。
给出方法思路,算法代码。
这个题目,在网上也搜到一些博文,不过有的方法有些问题,有的方法并不能得到正确答案,有的方法可以得到正确答案,但复杂度不满足。当然只是我觉得的,也有可能是我的问题。
方法一:
方法思路:用一个变量初始化为1,然后遍历数组比这个变量大的就保存到这个变量里。
算法代码:略。
举例:数组1,2,4,5,,用这个方法求出来的最小就是6,而正确答案是3。
问题:这个方法的问题在于没有考虑正数中间间隔的正数。
方法二:
方法思路:首先对数组进行从小到大的排序,确定大于0的数组a开始下标i,数组中最大的元素max,那么数组b的范围是1~max+1,然后从数组a中查找b[i]是否存在,若b[i]存在,则b[i]置零,否则进行下一个b[i]的查找,最后对b数组进行遍历,查找第一个非零的元素即为未出现的最小元素。
算法代码:略。
问题:“在从数组a中查找b[i]是否存在,若b[i]存在,则b[i]置零,否则进行下一个b[i]的查找”,这里的时间算法复杂度是O(n*n),同时空间复杂度O(n)。
方法三:
方法思路:首先找出数组里的最大值MAX,然后正整数数组b[MAX],初始化为0。然后遍历数组a:
If(a[i]>0 ){b[a[i]]=1;}
最后遍历数组b:
for(int j=0; j<MAX; j++) if (b[j] == 0 return j;)
这个算法是都可以得到正确答案的,问题在于空间复杂度不是O(1)。
方法四(正确答案):
方法思路:使用数组下标,通过交换,保证数组下标为i的元素值为i+1,即arr[i]=i+1,然后从前往后,不满足此条件的数即为所求。
关键代码:
for(int i =0; i<num; ++i)
{if (data[i]>=1 && data[i]<=num)}
{swap(data[i], data[data[i]-1]);}
注意:这里从第二个数组元素开始,同时很重要的判断条件data[i]>=1 && data[i]<=num,保证arr[i]=i+1。