做题过程中,发现自己把问题解决了,但是自己头脑还是好乱,所以打算把解题思路给写出来。如何发现问题,优化问题的。题目全当实在面试
01
—
题目
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:[2, 3, 1, 0, 2, 5, 3]输出:2 或 3
限制:
2 <= n <= 100000
来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
02
—
解题思路
需求阶段
拿到这道后, 我首先思考几个问题。
问题1:这道让我实现什么功能。 数据源以什么逻辑形式存放在内存中。
找到数组中重复的任何一个数字即可。数据源存放在数组中。
和面试官沟通:
数组的数据是否可以修改
假设面试官告诉我, 数据为传入参数。
时间复杂度和空间复杂度的要求
假如面试官告诉我,时间复杂度O(NlogN)
构思阶段
一、小白思路:
使用双重 for 循环。第一个元素和当前元素后面的比较 ,第二个和当前元素后面的比较,当发现有相等的情况下,满足条件。 这个思路比较简单。
但是思考一番时间复杂度和要求相差太大了。当前的时间复杂度为O(N^2)
二、进一步思考,时间复杂度可以从O(N^2)优化到 O(NlogN)吗?
时间浪费在什么地方 --- 小白思路主要时间浪费在 一个元素需要和N个元素比较。
那么可以实现一个元素仅仅和当前元素相邻的元素比较即可呢? --- 数组排序。然后依次比较相邻的元素。。其实有经验的,通过面试官告诉时间复杂可以知道本题最差使用什么算法可以通过,既NlogN时间复杂度类的算法,排序什么的。
1 数组排序
2 依次比较相邻的元素
把 2 的过程通过图来表示
代码实现
int findRepeatNumber(vector<int>& nums) { //1 排序 sort(nums.begin(), nums.end()); //2 依次查找相邻的是否相等。 // i 表示左区间 j 表示右区间 int i, j; i = 0; j = 0; for ( j =0 ; j < nums.size(); j++) { if (i == j) continue; if (i != j && nums[i] == nums[j]) { return nums[i]; } if (i != j && nums[i] != nums[j]) i = j; } return -1; }};
小伙子不错哦, 通过提交看来,你的时间复杂度还是太高了,那你在思考下,能不能在优化下,实现时间复杂度为O(N)呢!
陷入了沉思ing。。。
三、从O(NlogN)优化到O(N)
如何做到O(N)的时间复杂度呢?,实现这种级别的话只能循环一遍数组。
题目表示数组里面的值都在 0~n-1 范围内,那么能不能使用它来做点文章呢?
可以把里面的相同的数据放到一个地方, 那么数据存放的地方可以在去申请一块内存。这块内存是多大呢,根据里面的数值范围,取边界值。
总结一下:
其实就是使用简单 hash 算法。 hash 地址为一维数组的下标,hash 函数为f(x) = x
注:x 为 关键码因变量 f(x)为存储的地址
相同的数据放在同一个存储单元内存,你可能会问,如何同时存放,其实来一个数,相应存储单元加一。
最后遍历 hash 表。>2 表示 重复数据。
图解时间到了
由于hash[2]>2所以没有必要往下走了。
代码实现
class Solution {public: int findRepeatNumber(vector<int>& nums) { vector<int> hash(nums.size(),0); for(int i = 0;i { if(hash[nums[i]] == 1 ) return nums[i]; hash[nums[i]]++; } return -1; }};
性能
时间复杂度提高了接近一半 。但是搞不清楚为什么内存消耗为什么不变和上次比较。理论上是 辅助内存 消耗了O(N)才对啊。
四、面试官有要问了,能不能实现辅助内存为O(1)嫩
好吧!那我想一下、
主要使用 hash 表占用了,那不用 hash 表, 把数据放到数组 nums 中,
当前数组 当 hash 表,
流程:
//伪代码for( i = begin ; i/依次遍历{ while( arr[i] != i) { if(arr[i] != arr[arr[i]]) swap(arr[i] , arr[arr[i]]) else return arr[i]; }}
图解时间到了
代码实现
class Solution {public: int findRepeatNumber(vector<int>& nums) { //遍历整个数组 for (int i = 0; i < nums.size(); i++) { //把 nums[i] 放到 对应的下标中。5 > nums[5] while (i != nums[i]) { if (nums[i] == nums[nums[i]]) return nums[i]; swap(nums[i], nums[nums[i]]); } } return -1; }};
性能;
提高了10ms左右。
还不错。
03
—
总结
hash 函数
双指针
今天发现对 vector 不是很熟悉, 在这留个 tag , 找下相关资料在去总结。
留给自己的作业。
能不能再不改变数组情况下,且辅助内存为O(1)的情况下实现呢???
这个问题留着明天再来吧!!!!