剑指 Offer 03. 数组中重复的数字
1.这是先对数组排序然后遍历数组找出重复数(还记得当时做的时候巨搞笑,if里面总是写不对,现在为自己的愚蠢反思。)时间是O(nlogn)
lass Solution {
public int findRepeatNumber(int[] nums) {
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
if(nums[i]-nums[i+1]==0)
{
return nums[i];
}
}
return 0;
}
}
2.可以使用哈希表来解决,如果哈希表中没有这个数字,就加入到哈希表中,如果有,就返回这个重复数字。时间O(n),但是空间也增大了O(n)。
class Solution {
public int findRepeatNumber(int[] nums) {
Set<Integer> set = new HashSet<>();
int repeat = -1;
for (int num : nums) {
if (!set.add(num)) {
repeat = num;
break;
}
}
return repeat;
}
}
上面是学习的set的写法,学到了set.add(),当新元素添加返回T,否则返回F。下面是我自己之前写的,只能说,高低一眼就看出来了(~.~).
class Solution {
public int findRepeatNumber(int[] nums) {
Map<Integer, Integer> chongfu = new HashMap();
for(int i=0;i<nums.length;i++){
if(chongfu.get(nums[i])==null){
chongfu.put(nums[i],1);
}
else{
return nums[i];
}
}
return -1;
}
}
3.如果让空间变成O(1)就好了,所以又学到了一个原地交换的方法,真的感觉很奇妙,确实让我想,我夜想不出来啊。
遍历数组 nums ,设索引初始值为 i=0 :
若 nums[i]=i : 说明此数字已在对应索引位置,无需交换,因此跳过;
若 nums[nums[i]]=nums[i] : 代表索引 nums[i] 处和索引 i 处的元素值都为 nums[i] ,即找到一组重复值,返回此值 nums[i] ;
否则: 交换索引为 nums[i] 的元素值,将此数字交换至对应索引位置。
如果没有返回结果,则返回-1。
class Solution {
public int findRepeatNumber(int[] nums) {
int i = 0;
while(i < nums.length) {
if(nums[i] == i) {
i++;
continue;
}
if(nums[nums[i]] == nums[i]) return nums[i];
int t = nums[i];
nums[i] = nums[t];
nums[t] = t;
}
return -1;
}
}
只能说让我去理解,我也是理解了好半天,然后过一会还会忘掉,这方法着实很牛,也让我头大。(重点重点重点!!!)
当然,这题肯定少不了拓展,比如找出全部重复数啥的,下面是另一个拓展题。
不修改数组找重复数
题目要求和上面一样,就是不能修改数组(好头大啊)
看了下别人的思路,使用类似二分查找的方法,看完只能大声称赞:妙哉!
把数组从中间分成两段,1—m和m+1—n,看数组中1—m的个数有多少,如果超过m个,就说明前半段一定有重复的,否则就是后半段,然后继续二分二分,直到找到重复数字。(又要码代码了,痛啊),这个方法感觉抄了一遍还是不太理解,对一些东西还是迷迷糊糊的,还是要多看多记多码。
class T3t{
public int getDuplicate(int[] arr,int length){
if (arr == null || length <= 0) {
return -1;
}
int start = 1;
int end = arr.length - 1;
while (start <= end) {
int middle = start + (end - start) / 2;
int count = countRangeNumbers(arr, start, middle);
if (start == middle) {
if (count > 1) {
return start;
} else {
break;
}
}
if (count > (middle - start + 1)) {
end = middle - 1;
} else {
start = middle + 1;
}
}
return -1;
}
public int countRangeNumbers(int[] arr, int start, int end) {
int count = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] >= start && arr[i] <= end) {
count ++;
}
}
return count;
}
}
最后的最后,时间O(nlogn),空间O(1),时间换空间,当然也有弊端,这个方法找不了所有的重复数,比如在1—2,如果出现两个2,这个方法却找不到是各一个还是两个一或者两个二。
数组这一节,以这两个题收尾,过程还是有些绕弯了,但是也有所收获,下一节,字符串咯。