53. 最大子数组和
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
思路:这题力扣上有很多解法,我这里不做解释,我们这里采用扫描法。
注意:答案只需要给出最大和,不需要输出连续的子数组;其次在求和过程中只能是连续的
我们按照上面例子模拟一下处理过程:
①:-2进来了,一个负数我都不想要,但是还得加进来,目前就它一个,sum=-2;
②:1进来了,终于来个正数,加上之前的-2和还是负数,那不行,所以我只要1,去掉-2,sum=1;当前连续子数组的起始位置就是1了;
③:-3进来了,又是负数,并且和也是负数(1+-3=-2),那不行,我都不要了,1和-3都去掉,sum=0;
④:4进来了,正数,我欢迎,加上,sum=4,当前连续子数组的起始位置就是4,sum=4;
⑤:-1进来了,又是负数,虽然是负数,但是我可以接受,因为sum=4+-1=3,和还是正数,委屈一下吧;
⑥:2进来了,还好委屈了一下,来了个正数,sum=5,和还是正数;
。。。。省略后面步骤
总结:当前元素加入进来时,如果和是正数时我就接受,如果不是,那不好意思我都舍弃,从下一个元素开始,作为连续子数组的起始位置,在一遍扫描中,我始终追求最大和,该舍弃就舍弃,因为答案只需要最大和!这也是为什么当连续子数组的和是负数时,我都要舍弃,因为只要是负数,都会使得加入下一个元素的和结果变小!
最后你肯定想问如果数组都是负数怎么办,也好办,都是负数,最大和肯定是数组中的最大的一个数,注意是一个数!所以每次算出当前子数组的和都需要和记录的最大和比较,再选出最大。
代码:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT32_MIN;
int count=0;//当前连续子数组的和
for(int i=0;i<nums.size();i++){
count+=nums[i];
if(count>result){//更新最大和
result=count;
}
if (count <= 0) count = 0;//当前加入元素使得和小于0直接舍弃,并且重置和
}
return result;
}
};
56. 合并区间
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
思路:这题不难,只要判断一个区间的右边界和另一个区间的左边界就可以确定包含关系,在作比较之前先对原来区间按照左边界排序。
代码:
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> r;
if(intervals.size()==0) return r;
sort(intervals.begin(),intervals.end(),[](const vector<int>& a,const vector<int>& b){
return a[0]<b[0];//按左边界排序
});
r.push_back(intervals[0]);
for(int i=1;i<intervals.size();i++){
if(r.back()[1]>=intervals[i][0]){//前数组右边界大于后数组左边界,r.back()[1]取r中最后一维数组的右边界
r.back()[1]=max(r.back()[1],intervals[i][1]);//更新当前合并区间的右边界
}else{
r.push_back(intervals[i]);//不包含直接从后面插入
}
}
return r;
}
};
189. 轮转数组
给定一个整数数组 nums
,将数组中的元素向右轮转 k
个位置,其中 k
是非负数。
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3 输出: [5,6,7,1,2,3,4] 解释:向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4]
思路:这题解法很多,这里给出空间复杂度1的方法。也就是不用额外空间。
我们观察上面例子轮转完的数组,可以分成两部分,一是5,6,7;二是1,2,3,4;就像是两个数组拼接在一起,它们各自都有序,如果反转一下不就是7,6,5,4,3,2,1了嘛,所以我们可以用反转的方法去处理。
那么反转的范围如何界定,题目已经给出了,前k个反转就行对吧,那还有k>nums数组长度呢?我们只需要取余数就好。
代码:首先是反转函数
void reverse(vector<int>& nums,int start,int end){
while(start<end){
swap(nums[start],nums[end]);
start+=1;
end-=1;
}
}
其次是两步反转:整体翻转,局部翻转
class Solution {
public:
void reverse(vector<int>& nums,int start,int end){
while(start<end){
swap(nums[start],nums[end]);
start+=1;
end-=1;
}
}
void rotate(vector<int>& nums, int k) {
int size=nums.size();
k=k%size;
reverse(nums,0,size-1);
reverse(nums,0,k-1);
reverse(nums,k,size-1);
}
};