目录
1.题目
2.思路
方法1——排序nlogn
这个题第一个思路直接就是先排序这个数组,然后找到最长的连续值就可以。时间复杂度为O(nlogn),题目中要求为O(n)的话,需要进一步思考.
方法2——哈希表O(n)
主要借助哈希表查找一个元素是O(1)的时间复杂度。
- 先用一个哈希表记录每个元素是否出现过(用set也是可行,达到去重目的)。
- 然后判断当前元素num是否已经访问过
- 如果没有访问过,用一个left 和 right指针指向最长连续字符的左右边界。
- 如果num+ 1出现在哈希表中,并且没有访问过,那么就更新right, 更新num++,继续判断。
- 如果num - 1出现在哈希表中,并且没有访问过,那么就更新left, 更新num---,不断循环。
- 更新ans = Math.max(ans, right - left + 1)
时间复杂度——O(n)
虽然有两个while,但是可以保证每个元素只会访问一次,所以是O(n)
空间复杂度——O(n)
使用了一个哈希表,所以是O(n)
class Solution {
public int longestConsecutive(int[] nums) {
int n = nums.length;
Map<Integer,Integer>map = new HashMap();
for(int num : nums){
map.put(num, 1);
}
int ans = 0;
int left =0, right = 0;
for(int num : map.keySet()){
if(map.get(num) == 1){
// 没有被访问过
// map.put(nums[i], 0);
right = num;
left = num;
int temp = left;
while(map.containsKey(temp) && map.get(temp) == 1){
if(temp != num)
map.put(temp, 0);
left = temp;
temp--;
}
temp = right;
while(map.containsKey(temp) && map.get(temp) == 1){
if(temp != num)
map.put(temp, 0);
right = temp;
temp++;
}
// System.out.println(nums[i] +">>>" + left +">>>" + right);
ans = Math.max(ans, right - left + 1);
}
}
return ans;
}
}
方法3——并查集O(n)
并查集的思路,值得学习。并查集一般有两个函数和一个数组parent(或者是一个哈希表,用来记录每个节点的祖宗节点),一个是find(int x),用来找到节点x的祖宗节点。一个是union(x, y),用来连接节点x 和 节点 y,主要是更新两个节点的祖宗节点。
- 初始化哈希表map(num, num),一开始每个节点的祖宗节点就是自己本身。
- 遍历哈希表map, 如果num + 1 存在哈希表中,那么union(num, num + 1),如果num - 1存在哈希表中,那么union(num - 1, num).
- 最后再遍历哈希表,答案就是每个节点的祖宗节点 - 本身 + 1中的最大值。也就是ans = Math.max(ans, find(num) - num + 1)
时间复杂度——O(logn)
注意find(int x)中有while循环中有路径压缩。map.put(cur, find(cur));好像时间是介于O(1)和O(logn)之间,但是现实是运行时间非常满,141ms.可能跟合并操作有关系。
虽然这个题的并查集运行时间比较长,但是这个思路非常有意思,并查集需要学习!
空间复杂度——O(n)
有哈希表O(n)
class Solution {
// 记录每个节点的祖宗节点
Map<Integer, Integer>map = new HashMap();
public int longestConsecutive(int[] nums) {
// 初始化祖父节点
int n = nums.length;
for(int num : nums){
map.put(num, num);
}
if(map.keySet().size() <= 1) return map.keySet().size();
// 遍历数组,连接节点
for(int i = 0 ; i < n ; i++){
if(map.containsKey(nums[i] - 1))
union(nums[i] - 1, nums[i]);
if(map.containsKey(nums[i] + 1))
union(nums[i], nums[i] + 1);
}
// 更新ans
int ans = 0;
for(int num : nums){
ans = Math.max(ans, find(num) - num + 1);
}
return ans;
}
// 找到祖宗节点
public int find(int x){
while(x != map.get(x)){
int cur = map.get(x);
map.put(cur, find(cur));
x = cur;
}
return x;
}
// 连接两个节点x y
public void union(int x, int y){
int parentX = find(x);
int parentY = find(y);
if(parentX != parentY)
map.put(parentX, parentY);
}
}