128. 最长连续序列
给定一个未排序的整数数组 nums
,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n)
的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2] 输出:4 解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
思路:注意这里要求是复杂度为n,所以双层for循环暴力解法不可取。
重新思考,当遍历到当前元素时,我们需要去寻找它的下一个数字,例如遍历到100去找101,这里肯定是没有错的,所以我们能节省时间的就是去减少寻找次数,例如对于1,2,3,4这四个元素而言,都是在一个序列中,显然从1开始寻找是最长的,其他三个都比1要短。
这里就可以看出1和2,3,4的区别,就是1是序列起点,换句话说1前面没有0,而2前面有3,3前面有2,4前面有3,所以当遍历到2,3,4就跳过不去寻找,因为在遍历1的时候我们就会找到包含它们的序列,并且最长。那么跳过条件我们就知道了,如果当前元素减一也在数组中就跳过,例如4前面有3就跳过,我们只找起点元素。
查找我们就用unordered_set,无序集合上的所有操作在平均情况下都具有常数时间复杂度O(1),但在最坏情况下,时间复杂度可以达到线性时间O(n),这取决于内部使用的哈希函数,但实际上它们表现非常出色,通常提供常数时间的查找操作。
同时注意一下unordered_set是如何循环输出元素。
代码:
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
//初始化unordered_set
unordered_set<int> set;
//将数组中元素填入set中
for(int i=0;i<nums.size();i++){
set.insert(nums[i]);
}
//最长序列
int m=0;
for(auto iter = set.begin(); iter != set.end(); ++iter){
//如果没有当前元素减一的值在set中,就开始统计
if(!set.count(*iter-1)){
//当前元素下一个数字
int a=*iter+1;
//当前序列长度
int b = 1;
//按照当前元素寻找后面依次递增的数字
while(set.count(a)){
a+=1;
b+=1;
}
//更新
m=max(m,b);
}
}
return m;
}
};
283. 移动零
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12] 输出: [1,3,12,0,0]
思路:涉及到这种不复制数组就用双指针法处理,这里要求不移动其他元素的相对位置,双指针就只能从头开始。
代码:
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int left=0;
int right=0;
while(right<=(nums.size()-1)){
if(nums[right]!=0){
swap(nums[left], nums[right]);
++left;
}
++right;
}
}
};
11. 盛最多水的容器
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。
找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
思路:木桶能装多少水,是由最短的木板来决定,所以双指针法移动的是最短的那边,也就是比较一下元素值,再移动。
代码:
class Solution {
public:
int maxArea(vector<int>& height) {
int left=0;
int right=height.size() - 1;
int m=0;
while(left<right){
int n = min(height[left], height[right]) * (right - left);
m=max(m,n);
if(height[left]<=height[right]){
++left;
}
else{
--right;
}
}
return m;
}
};