【剑指offer】03.数组中重复的数字

234 阅读3分钟

题目描述

在这里插入图片描述

在这里插入图片描述

//03. 数组中重复的数字 // 找出数组中重复的数字。

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

// 牛客 // 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数 // 字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次 // 。请找出数组中第一个重复的数字。 例如,如果输入长度为7的数组{2,3, // 1,0,2,5,3},那么对应的输出是第一个重复的数字2。 // 返回描述: // 如果数组中有重复的数字,函数返回true,否则返回false。 // 如果数组中有重复的数字,把重复的数字放到参数duplication[0]中。(ps // :duplication已经初始化,可以直接赋值使用。)

排序法

把数组排成升序,再遍历找相邻重复数

// 时间复杂度 O(nlogn):3 ms, 在所有 Java 提交中击败了59.39%的用户
// 空间复杂度 O(1):45.9 MB, 在所有 Java 提交中击败了96.69%的用户
import java.util.Arsrays;

class Solution {
	public int findRepeatNumber(int[] nums) {
		if (nums == null || nums.length <= 0) {
			return -1;
		}
		Arrays.sort(nums);
		for (int i=0; i < nums.length-1; i++) {
			if (nums[i] == nums[i+1]) {
				return nums[i];
			}
		}
		return -1;
	}
}


集合法

很粗暴,直接存hashset,存不进就是遇到重复了

// 时间复杂度 O(n): 5 ms, 在所有 Java 提交中击败了49.49%的用户
// 空间复杂度 O(n):48.1 MB, 在所有 Java 提交中击败了23.18%的用户
import java.util.*;

class Solution {
	public int findRepeatNumber(int[] nums) {
        Set<Integer> set = new HashSet<>();
		int result = -1;
		if (nums == null || nums.length <= 0) { 
			return result;
        }
		for (int i=0; i <= nums.length-1; i++) {
			if (!set.add(nums[i])) {  // 如果存不进hashset,说明遇到重复
				result = nums[i];
				return result;  // 返回遍历数

			}
		}
		return result;
	}
}


// 牛客
// 牛客题目要求时间复杂度 O(N),空间复杂度 O(1),因此比较严格一点
// 运行时间 14ms
// 占用内存 10048KB
import java.util.HashSet;
public class Solution {
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if (length == 0)
            return false;
		HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < length; i++) {
            if (!set.add(numbers[i])) {
                duplication[0] = numbers[i];
                return true;
            }
        }
        return false;
    }
}

原地置换

找重复的数,且数取值在数组长度范围内,大部分数肯定是不重复的,将它们摆放成数字和索引相同的数组,即{0, 2, 3, 1}我们希望摆成{0, 1, 2, 3}。如果数组有两个2,那么原来2的位置有一个2,就会发现重复。

// 时间复杂度 O(n):1 ms, 在所有 Java 提交中击败了90.57%的用户
// 空间复杂度 O(1):45.8 MB, 在所有 Java 提交中击败了98.14%的用户
class Solution {
	public int findRepeatNumber(int[] nums) {
		if (nums == null || nums.length <= 0) {
			return -1;
		}
		int i = 0; // 初始化索引i
		
		while (i <= nums.length-1) {
			// 若遍历数与索引不等
			if (nums[i] != i) {
				// System.out.println(nums[i]);
				// 若遍历数与以遍历数为索引的对应数相等(遇重复)
				if (nums[i] == nums[nums[i]]) {
					return nums[nums[i]]; // 直接返回结果
				}
				//交换:遍历数与以遍历数为索引的对应数
				swap(nums, i);  
			} // (交换后)确认遍历数与索引相等之后,再右移索引
			else {
				i++;
			}
		}
		return -1;
	}
	
	// 定义交换方法
	private void swap(int[] list, int i) {
		int temp = list[list[i]];
		list[list[i]] = list[i];
		list[i] = temp;
    }
}


// 牛客
import java.util.HashSet;
public class Solution {
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if (length == 0)
            return false;
        int i = 0;
        while (i < length) {
            if (numbers[i] != i){
                if (numbers[i] == numbers[numbers[i]]) {
                    duplication[0] = numbers[numbers[i]];
                    return true;
                }
                swap(numbers, i);
            }
            else 
                i++;
        }
        return false;
    }
    
    // 使得numbers[i]和numbers[numbers[i]]交换
    private void swap(int[] numbers, int i) {
        int temp = numbers[numbers[i]];
        numbers[numbers[i]] = numbers[i];
        numbers[i] = temp;
    }
}