209 长度最小的子数组
思考:
不断将子数组尾部延伸到元素和大于等于target,然后再缩小子数组头部。
当子数组元素和小于target或延伸到原数组最后一个元素但仍未满足target时该子数组不合法。
试着用双指针——滑动窗口法(可在一个数组上操作,同时降低时间复杂度):
终结窗口指针遍历整个数组,起始窗口指针缩小合法窗口寻找长度最小的合法子串。
我的代码:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int count=0,sum=0,result=INT32_MAX;
for(int i=0,j=0;j<=nums.size()/*&&sum>=target*/;){
if(sum<target&&j<nums.size()){
sum+=nums[j];
j++;
}
else if(sum>=target&&i<nums.size()){
count=j-i;
result=result<count?result:count;
sum-=nums[i];
i++;
}
if(j==nums.size()&&sum<target)
break;
}
return result<count?result:count;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(1)
59 螺旋矩阵II
思考:联系二分查找学习到的循环不变量原则
这类题关键在于如何设置循环边界条件。
当初刚学编程的时候就做过类似的矩阵题(好像是蛇形矩阵之类的,当时就很头疼...果然很久不写又卡了好久)
对于这题,要注意到顺时针填数矩阵有两层循环,内层循环是每转一圈有四条边,外层循环是有很多圈要转。为确保转某一圈时四条边长度相等,采取左闭右开的边端点取值比较合适。
以下图n=5和n=6为例,注意到转几圈和n有关,中央是否有空缺和n的奇偶性有关。
同时注意到每圈的边界在逐圈缩小,需要适当设置和增减内外边界的值。
我的代码:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
//坚持循环不变量原则,确定边界开闭后不改变
//尝试左闭右开
std::vector<vector<int>> matrix(n,vector<int>(n,0));
int num=1,i=0,j=0;
int loop=n/2;//循环一周(上下左右)次数和n的值有关——见例图
int edgeout=n-1,edgein=0;//内外边界
while(loop--){
for(;j<edgeout;j++)//上边从左往右
matrix[i][j]=num++;
for(;i<edgeout;i++)//右边从上到下
matrix[i][j]=num++;
for(;j>edgein;j--)//下边从右往左
matrix[i][j]=num++;
for(;i>edgein;i--)//左边从下到上
matrix[i][j]=num++;
edgeout--;
edgein++;
i++;
j++;
}
if(n % 2)//若n为奇数,则最中间会有一个元素需要单独填入
matrix[i][j]=num;
return matrix;
}
};
- 时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
- 空间复杂度 O(1)
KamaCoder58 区间和
思考:一种很典型的数组类型题目 计算区间元素和
解决这类问题时,需要用到一个很有用的技巧:前缀和。
前缀和的思想是重复利用计算过的子数组之和,从而降低区间查询需要累加计算的次数。
前缀和法相比于暴力解法遍历数组求区间和,最大的优点是可以极大优化时间复杂度。
核心解法是设置一个前缀和(原数组下标从0到其他下标所在区间的元素和)数组sum,当要求某一个指定区间时,例如原数组下标2到下标5之间的区间和,可以通过sum[5]-sum[1]求得。
注意,在使用前缀和求解的时候要特别注意求解区间的选取。下标2到下标5之间的元素包括下标2的元素,所以减数是sum[1]而不是sum[2]。
(之后有空补个手绘图)
我的代码:
#include<iostream>
#include<vector>
using namespace std;
int main(){
//使用前缀和数组来求指定区间和
int n,a,b,result;
int temp=0;
cin>>n;
std::vector<int> arr(n);
std::vector<int> sum(n);
//for(int i=0;i<n;i++)
//时间超限的解决办法要考虑删除不必要循环
for(int i=0;i<n;i++){
//cin>>arr[i];
//当处理的数据量很大时,使用scanf和printf函数会比cin和cout节省运行时间
scanf("%d",&arr[i]);
//temp=0;
// for(int j=0;j<=i;j++)
temp+=arr[i];
sum[i]=temp;
}
while(scanf("%d%d",&a,&b)==2){//每当有一次输入流输入数据,循环执行一次
//使用前缀和数组中的元素进行相减来求指定区间
if(a==0)
result=sum[b];
else
result=sum[b]-sum[a-1];
printf("%d\n",result);
}
return 0;
}
*关于oj平台的判定,出现时间超限的问题时,要考虑减少不必要循环,并且当处理的数据量很大时,使用scanf和printf函数会比cin和cout节省运行时间。
KamaCoder44 开发商购买土地
(没时间写这个题的博客了之后补上......嗯)