刚开始刷题,一定要先自己想,然后再看别人的题解思路,然后慢慢优化
方法一:哈希表(最自然,但是要额外空间)
最容易想到用哈希表判重,这种方法是最自然的。
特别地,在数组的长度不超过32的时候,使用位运算的技巧可以实现 O(1)空间复杂度判重,但是这道题不是回溯算法的问题,题目给出的测试用例的长度肯定不止32位,因此,不建议使用位运算的技巧。
分析:这种方法不修改原始数组,但是使用了O(N)空间,使用空间换时间,是最正常的思路,时间复杂度是 O(N)。
方法二:排序(也比较容易想到,但是要排序,复杂度高)
排序以后,再遍历一遍就知道哪个重复了。
分析:这个方法其实比较容易想到,但是时间复杂度是O(NlogN),同时也修改了原始数组。
方法三:把数组视为哈希表(有一类问题是这么做的,但是会修改数组)
由于数组元素的值都在指定的范围内,这个范围恰恰好与数组的下标可以一一对应;
因此看到数值,就可以知道它应该放在什么位置,这里数字nums[i] 应该放在下标为 i 的位置上,这就像是我们人为编写了哈希函数,这个哈希函数的规则还特别简单。
分析:这个思路利用到了数组的元素值的范围恰好和数组的长度是一样的,因此数组本身可以当做哈希表来用。遍历一遍就可以找到重复值,但是修改了原始数组。
class Solution {
public int findRepeatNumber(int[] nums) {
int len = nums.length;
for(int i=0; i<len; i++){
//不断循环,直到数组的位置有正确的值
while(nums[i] != i){
//替换之前先查看该位置上是否有属于该位置的数,如果有则重复值就是这个数,直接返回即可
if(nums[i] == nums[nums[i]]){
return nums[i];
}
swap(nums, i, nums[i]);
}
}
return -1; //表示没有重复值
}
//用于交换数组中的两个值
public void swap(int nums[], int index1, int index2){
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}