1、剑指offer第42题
leetcode 地址连续子数组的最大和
这道题目基本是考察动态规划的最简单题目啦😁
动态规划:
-
状态转移方程:
dp[i] = max(dp[i-1] + nums[i], nums[i])
,其中dp[i]
表示以索引i
为结束点基准的子数组的最大值。 -
初始状态:
dp[0]= nums[0]
。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
vector<int> res(0);
if(nums.empty())
return 0;
res.push_back(nums[0]);
for(int i = 1; i < nums.size(); i++)
{
res.push_back(max(res[i - 1] + nums[i], nums[i]));
}
return *max_element(res.begin(), res.end());
}
};
当然,上面答案其实新开辟了vector<int> res
内存空间,如果想继续优化,可以仿照下面思路:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
for(int i = 1; i < nums.size(); i++)
{
nums[i] = max((nums[i - 1] + nums[i]), nums[i]);
}
return *max_element(nums.begin(),nums.end());
}
};
或者还有一个思路,循环遍历数组,当累加和大于0时保存累加和,否则重置,代码如下:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int res = nums[0];
int tmp = res;
for(int i = 1; i < nums.size(); i++)
{
if(tmp >= 0)
tmp += nums[i];
else
tmp = nums[i];
res = max(tmp, res);
}
return res;
}
};
2. 子数组最大平均数 I(643)
leetcode 地址数组最大平均数 I
这道题几乎和上面那道如出一辙。
先求出前k
个数的和sum
,然后从k+1
个数开始,不断滑窗更新sum。
class Solution {
public:
double findMaxAverage(vector<int>& nums, int k) {
double sum = accumulate(nums.begin(), nums.begin() + k, 0);
double res = sum;
for (int i = k; i < nums.size(); ++i) {
sum += nums[i] - nums[i - k];
res = max(res, sum);
}
return res / k;
}
};
剑指 Offer 59 - I. 滑动窗口的最大值
Offer 59 - I. 滑动窗口的最大值这道题和leetcode 239. 滑动窗口最大值一毛一样。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res(0);
if(nums.empty() || k == 0)
{
return res;
}
auto max_iter = max_element(nums.begin(), nums.begin() + k);
res.push_back(*max_iter);
for(auto iter = nums.begin() + k; iter != nums.end(); iter++)
{
if(iter - max_iter >= k)
{
max_iter = max_element(max_iter + 1, iter + 1);
}
else
{
if(*iter > *max_iter)
max_iter = iter;
}
res.push_back(*max_iter);
}
return res;
}
};
代码思路
首先,程序定义了一个空的vector res
,用于存储滑动窗口中的最大值。
然后,程序检查数组nums
是否为空,或者滑动窗口的大小k是否为0。如果是,则直接返回res。
接着,程序使用max_element
函数找到滑动窗口中的最大值,并将其添加到res中。
然后,程序遍历数组nums
,对于每个元素,程序首先检查当前元素是否在滑动窗口中。如果是,则使用max_element
函数找到滑动窗口中的最大值,并将其更新为当前元素。
最后,程序将滑动窗口中的最大值添加到res中,并返回res。
以上代码的简化版本如下
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res;
if (nums.empty() || k == 0) {
return res;
}
int max_val = *max_element(nums.begin(), nums.begin() + k);
res.push_back(max_val);
for (int i = k; i < nums.size(); ++i) {
if (nums[i - k] == max_val) {
max_val = *max_element(nums.begin() + i - k + 1, nums.begin() + i + 1);
} else if (nums[i] > max_val) {
max_val = nums[i];
}
res.push_back(max_val);
}
return res;
}
};
这个C++程序首先定义了一个空的vector res
,用于存储滑动窗口中的最大值。然后,程序检查数组nums是否为空,或者滑动窗口的大小k是否为0。如果是,则直接返回res。接着,程序使用max_element
函数找到滑动窗口中的最大值,并将其添加到res中。然后,程序遍历数组nums
,对于每个元素,程序首先检查当前元素是否在滑动窗口中。如果是,则使用``max_element函数找到滑动窗口中的最大值,并将其更新为当前元素。最后,程序将滑动窗口中的最大值添加到res中,并返回res。
比较遗憾,上述两种写法都无法在leetcode AC,AC代码如下
AC代码
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> dq;
vector<int> res;
for (int i = 0; i < nums.size(); ++i) {
if (!dq.empty() && dq.front() == i - k) {
dq.pop_front();
}
while (!dq.empty() && nums[dq.back()] < nums[i]) {
dq.pop_back();
}
dq.push_back(i);
if (i >= k - 1) {
res.push_back(nums[dq.front()]);
}
}
return res;
}
思路解释
这个C++程序首先定义了一个双端队列dq,用于存储滑动窗口中的最大值的索引。然后,程序遍历数组nums,对于每个元素,程序首先检查队列是否为空,以及队列中的第一个元素是否是当前滑动窗口的左边界。如果是,则从队列中弹出第一个元素。然后,程序遍历队列,如果队列中的最后一个元素小于当前元素,则从队列中弹出最后一个元素。