Leetcode 209 长度最小的子数组
采用滑动窗口法解决这个问题。首先,如果采用暴力求解,即两个for循环,第一个for控制子数组起始位置,第二个for控制子数字结束位置,保留并更新大于等于target的最小子数组长度。这个方法时间复杂度为O(n^2),如果要构造O(n)的算法,采用动态窗口法。只使用一个for循环完成,for循环控制子数组的结束位置j,j不断增加,当子数组的和大于等于target时,收缩子数组的起始位置直到小于target,同样不断保留和更新最小数字长度。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX;
int subLength = 0;
int sum = 0;
int i = 0;
for(int j = 0; j <= nums.size() - 1; j++){
sum += nums[j];
while(sum >= target){
subLength = j - i + 1;
result = result < subLength? result : subLength;
sum -= nums[i++];
}
}
return result == INT32_MAX? 0 : result;
}
};
拓展练习:Leetcode 904 水果成篮
分析题目,其实是要求数组中满足只有两个元素的子数组的最大长度,但是最后试了半天没有完全通过用例。一直在纠结怎么检测有两个元素,需要用两个变量记录种类,没有想到键值配对可以用哈希表。最后学习了官方解答,同样是滑动窗口,遍历right,如果unordered_map里的种类超过两个开始移动left,其中注意删除value为0的key。
class Solution {
public:
int totalFruit(vector<int>& fruits) {
unordered_map<int, int> basket;
int left = 0;
int result = 0;
for (int right = 0; right < fruits.size(); right++){
basket[fruits[right]]++;
while(basket.size() > 2){
auto it = basket.find(fruits[left]);
it->second --;
if(it->second == 0){
basket.erase(it);
}
left++;
}
result = result > (right - left + 1)? result : (right - left + 1);
}
return result;
}
};
Leetcode 59 螺旋矩阵
首先自己做了一遍,运行成功。关键是要理清思路,循环不变量原则,固定区间为左闭右开。另外需要特别注意,for循环先执行一次i++,再判断条件;
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int loop = n/2;
int tx = 0, ty = 0;
int num = 1;
int offsetR = n;
int offsetL = 0;
while(loop--){
for (; ty < offsetR - 1; ty++){
res[tx][ty] = num;
num++;
}
//tx++;
for(; tx < offsetR - 1; tx++){
res[tx][ty] = num;
num++;
}
//ty++;
for(; ty > offsetL; ty--){
res[tx][ty] = num;
num++;
}
//tx--;
for(; tx > offsetL; tx--){
res[tx][ty] = num;
num++;
}
//tx++;
offsetL++;
offsetR--;
tx++;
ty++;
}
if(n%2 == 1)
res[n/2][n/2] = n*n;
return res;
}
};
Kama 58 区间和
第一次做acm模式,先稍微补了补输入输出的设置,然后暴力求解超时。
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> nums(n);
for(int i = 0; i < n; i++){
cin >> nums[i];
}
while(cin >> a >> b){
int sum = 0;
for(int i = a; i <= b; i++){
sum += nums[i];
}
cout<<sum<<endl;
}
}
之后学习了前缀和
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> nums(n);
vector<int> sum(n);
for(int i = 0; i < n; i++){
cin >> nums[i];
}
int s = 0;
for(int i = 0; i < n; i++){
s += nums[i];
sum[i] = s;
}
while(cin >> a >> b){
if(a != 0)
cout<<sum[b] - sum[a - 1]<<endl;
else
cout<<sum[b]<<endl;
}
}
Kama 44 开发商购买土地
和区间和一样,先分行分列求出前缀和,然后再枚举每个行列的划分情况进行对比,需要注意的是使用INT_MAX关键字,需要引用<climits>。
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main(){
int n, m;
cin>>n>>m;
vector<vector<int>> ground(n, vector<int>(m, 0));
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
cin>>ground[i][j];
}
}
vector<int> h(n, 0);
int sum = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
sum += ground[i][j];
}
h[i] = sum;
}
vector<int> v(m, 0);
sum = 0;
for(int j = 0; j < m; j++){
for(int i = 0; i < n; i++){
sum += ground[i][j];
}
v[j] = sum;
}
int res = INT_MAX;
int ans = INT_MAX;
for(int i = 1; i <= n - 1; i++){
ans = abs((h[n-1] - h[i-1]) - h[i-1]);
res = res < ans? res : ans;
}
for(int j = 0; j <= m - 1; j++){
ans = abs((v[m-1] - v[j-1]) - v[j-1]);
res = res < ans? res : ans;
}
cout<<res<<endl;
}