Day2
class Solution {
public :
int minSubArrayLen ( int target, vector< int > & nums) {
int ans = INT_MAX;
int sum = 0 ;
for ( int left = 0 , right = 0 ; right < nums. size ( ) ; ++ right)
{
sum += nums[ right] ;
if ( sum >= target)
{
ans = min ( ans, right- left+ 1 ) ;
while ( left <= right)
{
sum -= nums[ left] ;
++ left;
if ( sum >= target)
ans = min ( ans, right- left+ 1 ) ;
else
break ;
}
}
}
if ( ans == INT_MAX)
return 0 ;
return ans;
}
} ;
解题代码就是对螺旋填入数字行为的模拟 由于是螺旋填入,每侧(上下左右)都应该保持相同的填入准则
比如每次填写,该行元素包含头不包含尾(即左闭右开) 填写列的行为也应该与填写行一样 最后考虑每转一圈,填写的起始位置和结束位置变化关系
以上侧填行为例,我们向右填写。每转一圈后,开始位置向右移动一格,结束位置向左移动一格
class Solution {
public :
vector< vector< int >> generateMatrix ( int n) {
if ( n == 1 )
return { { 1 } } ;
vector< vector< int >> board ( n, vector < int > ( n, 0 ) ) ;
int loop_num = n % 2 == 1 ? 2 * ( n - 1 ) + 1 : 2 * n;
int offset = 0 ;
int row_start = 0 ;
int col_start = 0 ;
int num = 1 ;
for ( int cnt= 0 ; cnt< loop_num; ++ cnt)
{
for ( int i= 0 + offset; i< n- offset- 1 ; ++ i)
{
board[ 0 + offset] [ i] = num;
++ num;
}
for ( int i= 0 + offset; i< n- offset- 1 ; ++ i)
{
board[ i] [ n- offset- 1 ] = num;
++ num;
}
for ( int i= n- offset- 1 ; i> 0 + offset; -- i)
{
board[ n- offset- 1 ] [ i] = num;
++ num;
}
for ( int i= n- offset- 1 ; i> 0 + offset; -- i)
{
board[ i] [ 0 + offset] = num;
++ num;
}
++ offset;
}
if ( n % 2 == 1 )
board[ n / 2 ] [ n / 2 ] = num;
return board;
}
} ;
前缀和的典型应用,我们通过数组跟踪当前位置累加的和
对于任意一个i
,preSum[i]
代表从开始到位置i
的元素和,即sum{0, i}
对任意一个区间[m, n]
,通过preSum
计算就是sum{m, n} = preSum[n] - preSum[m-1]
为什么不是preSum[n] - preSum[m]
? 因为preSum[m]
包含位置m的元素,不应该减去
# include <iostream>
# include <vector>
int main ( )
{
int n;
std:: cin >> n;
std:: vector< int > preSum ( n, 0 ) ;
for ( int i= 0 ; i< preSum. size ( ) ; ++ i)
{
int num;
std:: cin >> num;
if ( i == 0 )
preSum[ i] = num;
else
preSum[ i] = preSum[ i- 1 ] + num;
}
int a, b;
while ( std:: cin >> a >> b)
{
if ( a == 0 )
std:: cout << preSum[ b] << std:: endl;
else
std:: cout << preSum[ b] - preSum[ a- 1 ] << std:: endl;
}
}
一维前缀和的二维应用,重点在于土地是不可重复分割,且只能横向、纵向分割的 这就表示我们最终也只有两种分割方式:横分和纵分。只不过分割的位置不同 所以我们可以分别计算横分和的前缀和,然后取最小值,得到结果
求前缀和时,我们将2D数组压缩成一维,原因是我们需要的是分割出来那部分的评分总和(土地的评分),而不在乎究竟这块地里哪个位置评分高 取最小值时我们用了2*lsum
方便直接计算分割后两块地的差值
假设lsum
正好是把土地评分平分了,那么2*lsum=sum
,我们的差值就是0 否则我们就能得到一个分割后的评分差,然后取最小即可
# include <iostream>
# include <vector>
# include <climits>
using namespace std;
int main ( )
{
int n, m;
cin >> n >> m;
vector< vector< int >> board ( n, vector < int > ( m, 0 ) ) ;
int sum = 0 ;
for ( int i= 0 ; i< n; ++ i)
{
for ( int j= 0 ; j< m; ++ j)
{
cin >> board[ i] [ j] ;
sum += board[ i] [ j] ;
}
}
vector< int > rowPre ( n, 0 ) ;
for ( int i= 0 ; i< n; ++ i)
for ( int j= 0 ; j< m; ++ j)
rowPre[ i] += board[ i] [ j] ;
vector< int > colPre ( m, 0 ) ;
for ( int i= 0 ; i< m; ++ i)
for ( int j= 0 ; j< n; ++ j)
colPre[ i] += board[ j] [ i] ;
int ans = INT_MAX;
int lsum = 0 ;
for ( int i= 0 ; i< rowPre. size ( ) ; ++ i)
{
lsum += rowPre[ i] ;
ans = min ( ans, abs ( sum - 2 * lsum) ) ;
}
lsum = 0 ;
for ( int i= 0 ; i< colPre. size ( ) ; ++ i)
{
lsum += colPre[ i] ;
ans = min ( ans, abs ( sum - 2 * lsum) ) ;
}
cout << ans;
return 0 ;
}