1. Day19
1.1 小易的升级之路(数学 + 模拟)
题目链接 : WY3 小易的升级之路 题目描述:
解法:
C++ 算法代码:
# include <iostream>
using namespace std;
int gcd ( int a, int b)
{
if ( b == 0 )
{
return a;
}
return gcd ( b, a % b) ;
}
int main ( )
{
int n, a;
while ( cin >> n >> a)
{
int x = 0 ;
for ( int i = 0 ; i < n; i++ )
{
cin >> x;
if ( a >= x)
{
a += x;
}
else
{
a += gcd ( a, x) ;
}
}
cout << a << endl;
}
return 0 ;
}
1.2 礼物的最大价值(动态规划 - 路径问题)
题目链接 : JZ47 礼物的最大价值 题目描述:
解法:
C++ 算法代码:
class Solution {
public :
int maxValue ( vector< vector< int > > & grid)
{
int m = grid. size ( ) ;
int n = grid[ 0 ] . size ( ) ;
vector< vector< int >> dp ( m + 1 , vector < int > ( n + 1 , 0 ) ) ;
for ( int i = 1 ; i <= m; i++ )
{
for ( int j = 1 ; j <= n; j++ )
{
dp[ i] [ j] = max ( dp[ i - 1 ] [ j] , dp[ i] [ j - 1 ] ) + grid[ i - 1 ] [ j - 1 ] ;
}
}
return dp[ m] [ n] ;
}
} ;
1.3 对称之美(字符串 + 哈希)
题目链接 : 对称之美 题目描述:
解法:
算法思路:左右指针判断回⽂串。判断左右指针相等的时候,应该看看两个字符串中有没有相同的字符。 C++ 算法代码:
# include <iostream>
# include <cstring>
# include <string>
using namespace std;
string s;
bool vis[ 110 ] [ 26 ] ;
int t, n;
bool check ( int left, int right)
{
for ( int i = 0 ; i < 26 ; i++ )
{
if ( vis[ left] [ i] && vis[ right] [ i] )
{
return true ;
}
}
return false ;
}
int main ( )
{
cin >> t;
while ( t-- )
{
memset ( vis, 0 , sizeof ( vis) ) ;
cin >> n;
for ( int i = 0 ; i < n; i++ )
{
cin >> s;
for ( auto & ch : s)
{
vis[ i] [ ch - 'a' ] = true ;
}
}
int left = 0 ;
int right = n - 1 ;
while ( left < right)
{
if ( ! check ( left, right) )
{
break ;
}
left++ ;
right-- ;
}
if ( left < right)
{
cout << "No" << endl;
}
else
{
cout << "Yes" << endl;
}
}
return 0 ;
}
2. Day20
2.1 经此⼀役小红所向无敌(模拟)
题目链接 : 经此⼀役小红所向无敌 题目描述:
解法:
C++ 算法代码:
# include <iostream>
using namespace std;
int main ( )
{
long long a, h, b, k;
cin >> a >> h >> b >> k;
long long ret = 0 ;
long long n = min ( h / b, k / a) ;
ret += n * ( a + b) ;
h -= n * b;
k -= n * a;
if ( h > 0 && k > 0 )
{
h -= b;
k -= a;
ret += a + b;
}
if ( h > 0 || k > 0 )
{
ret += 10 * ( h > 0 ? a : b) ;
}
cout << ret << endl;
return 0 ;
}
2.2 连续子数组最大和(动态规划 - 线性dp)
题目链接 : DP6 连续子数组最大和 题目描述:
解法:
算法思路。简单线性 dp。
状态表示: dp[i] 表示:以 i 位置为结尾的所有⼦数组中,最⼤和是多少。 状态转移方程: dp[i] = max(dp[i - 1] + arr[i], arr[i]) C++ 算法代码:
# include <iostream>
using namespace std;
const int N = 2e5 + 10 ;
int main ( )
{
int n;
cin >> n;
int arr[ N] = { 0 } ;
for ( int i = 1 ; i <= n; i++ )
{
cin >> arr[ i] ;
}
int dp[ N] = { 0 } ;
int ret = - 101 ;
for ( int i = 1 ; i <= n; i++ )
{
dp[ i] = max ( dp[ i - 1 ] , 0 ) + arr[ i] ;
ret = max ( ret, dp[ i] ) ;
}
cout << ret << endl;
return 0 ;
}
2.3 非对称之美(规律)
题目链接 : 非对称之美 题目描述:
解法:
C++ 算法代码:
# include <iostream>
using namespace std;
int main ( )
{
string s;
cin >> s;
int n = s. size ( ) ;
bool flag = false ;
for ( int i = 0 ; i < n; i++ )
{
if ( s[ i] != s[ 0 ] )
{
flag = true ;
break ;
}
}
if ( flag == false )
{
cout << 0 << endl;
return 0 ;
}
flag = true ;
int left = 0 ;
int right = n - 1 ;
while ( left < right)
{
if ( s[ left] == s[ right] )
{
left++ ;
right-- ;
}
else
{
flag = false ;
break ;
}
}
if ( flag)
{
cout << n - 1 << endl;
}
else
{
cout << n << endl;
}
return 0 ;
}
3. Day21
3.1 爱丽丝的人偶(贪心 + 构造)
题目链接 : 爱丽丝的人偶 题目描述:
解法:
C++ 算法代码:
# include <iostream>
using namespace std;
int main ( )
{
int n = 0 ;
cin >> n;
int left = 1 ;
int right = n;
while ( left <= right)
{
cout << left << " " ;
left++ ;
if ( left <= right)
{
cout << right << " " ;
right-- ;
}
}
return 0 ;
}
3.2 集合(排序)
题目链接 : JD7 集合 题目描述:
解法:
C++ 算法代码:
# include <iostream>
# include <set>
using namespace std;
int main ( )
{
int n, m;
cin >> n >> m;
int x = 0 ;
set< int > s;
for ( int i = 0 ; i < n; i++ )
{
cin >> x;
s. insert ( x) ;
}
for ( int i = 0 ; i < m; i++ )
{
cin >> x;
s. insert ( x) ;
}
for ( auto iter = s. begin ( ) ; iter != s. end ( ) ; ++ iter)
{
cout << * iter << " " ;
}
return 0 ;
}
3.3 最长回文子序列(动态规划 - 区间 dp)
题目链接 : DP22 最长回文子序列 题目描述:
解法:
算法思路。基础的区间 dp 问题:
状态表示:
dp[i][j] 表示:字符串 [i, j] 范围内的最长回文子序列的长度; 状态转移方程:
当 i == j 的时候,只有⼀个字符,长度为 1; 当 i < j 的时候,分情况讨论:
s[i] == s[j]:dp[i][j] = dp[i + 1][j - 1]; s[i] != s[j]:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
返回值: dp[0][n - 1] 。 C++ 算法代码:
# include <iostream>
using namespace std;
const int N = 1005 ;
int main ( ) {
string s;
cin >> s;
int dp[ N] [ N] = { 0 } ;
int n = s. size ( ) ;
for ( int i = n - 1 ; i >= 0 ; i-- )
{
dp[ i] [ i] = 1 ;
for ( int j = i + 1 ; j < n; j++ )
{
if ( s[ i] == s[ j] )
{
dp[ i] [ j] = dp[ i + 1 ] [ j - 1 ] + 2 ;
}
else
{
dp[ i] [ j] = max ( dp[ i + 1 ] [ j] , dp[ i] [ j - 1 ] ) ;
}
}
}
cout << dp[ 0 ] [ n - 1 ] << endl;
return 0 ;
}
4. Day22
4.1 添加字符(字符串)
题目链接 : [编程题]添加字符 题目描述:
解法:
算法思路:枚举所有字符串 a 与字符串 b 相对应的位置。 C++ 算法代码:
# include <iostream>
using namespace std;
int main ( )
{
string A;
string B;
cin >> A >> B;
int m = A. size ( ) ;
int n = B. size ( ) ;
int ret = m;
for ( int i = 0 ; i <= n - m; i++ )
{
int tmp = 0 ;
for ( int j = 0 ; j < m; j++ )
{
if ( A[ j] != B[ i + j] )
{
tmp++ ;
}
}
ret = min ( tmp, ret) ;
}
cout << ret << endl;
return 0 ;
}
4.2 数组变换(贪心 + 位运算)
题目链接 : [编程题]数组变换 题目描述:
解法:
算法思路:如果能够变换成功,那么最大的数除以剩下的数的商,⼀定都是 2 的 n 次方。 C++ 算法代码:
# include <iostream>
using namespace std;
int n = 0 ;
int b = 0 ;
int arr[ 51 ] ;
bool check ( )
{
for ( int i = 0 ; i < n; i++ )
{
if ( b != arr[ i] )
{
if ( b % arr[ i] )
{
return false ;
}
int tmp = b / arr[ i] ;
if ( tmp % 2 )
{
return false ;
}
}
}
return true ;
}
int main ( )
{
cin >> n;
for ( int i = 0 ; i < n; i++ )
{
cin >> arr[ i] ;
b = max ( b, arr[ i] ) ;
}
if ( check ( ) )
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
return 0 ;
}
4.3 装箱问题(动态规划 - 01 背包)
题目链接 : [NOIP2001]装箱问题 题目描述:
解法:
C++ 算法代码:
# include <iostream>
# include <vector>
using namespace std;
const int N = 35 , M = 2e4 + 10 ;
int main ( )
{
int v = 0 ;
cin >> v;
int n = 0 ;
cin >> n;
int arr[ N] = { 0 } ;
for ( int i = 1 ; i <= n; i++ )
{
cin >> arr[ i] ;
}
int dp[ M] = { 0 } ;
for ( int i = 1 ; i <= n; i++ )
{
for ( int j = v; j >= arr[ i] ; j-- )
{
dp[ j] = max ( dp[ j] , dp[ j - arr[ i] ] + arr[ i] ) ;
}
}
cout << v - dp[ v] << endl;
return 0 ;
}
5. Day23
5.1 打怪(模拟)
题目链接 : 打怪 题目描述:
解法: 算法思路:根据题意模拟,注意⼀下细节就好了。C++ 算法代码:
# include <iostream>
using namespace std;
int h, a, H, A;
int check ( )
{
if ( a >= H)
{
return - 1 ;
}
int m = ( H / a) + ( H % a != 0 ? 1 : 0 ) ;
int n = m - 1 ;
int x = n * A;
int ret = h / x - ( h % x == 0 ? 1 : 0 ) ;
return ret;
}
int main ( )
{
int t = 0 ;
cin >> t;
while ( t-- )
{
cin >> h >> a >> H >> A;
cout << check ( ) << endl;
}
return 0 ;
}
5.2 字符串的分类(哈希 / 排序)
题目链接 : [编程题]字符串分类 题目描述:
解法:
算法思路:将字符串排序后,丢进能去重的哈希表里面就好了。 C++ 算法代码:
# include <iostream>
# include <unordered_set>
# include <algorithm>
using namespace std;
int main ( )
{
int n = 0 ;
cin >> n;
unordered_set< string> strs;
string s;
while ( n-- )
{
cin >> s;
sort ( s. begin ( ) , s. end ( ) ) ;
strs. insert ( s) ;
}
cout << strs. size ( ) << endl;
return 0 ;
}
5.3 城市群数量(联通块)
题目链接 : NC345 城市群数量 题目描述:
解法:
算法思路:经典 floodfill 算法,可以用 dfs 或者 bfs 解决。 C++ 算法代码:
class Solution {
public :
bool vis[ 210 ] = { false } ;
int citys ( vector< vector< int > > & c)
{
int m = c. size ( ) ;
int ret = 0 ;
for ( int i = 0 ; i < m; i++ )
{
if ( ! vis[ i] )
{
ret++ ;
dfs ( c, i) ;
}
}
return ret;
}
void dfs ( vector< vector< int >> & c, int pos)
{
vis[ pos] = true ;
for ( int i = 0 ; i < c. size ( ) ; i++ )
{
if ( ! vis[ i] && c[ pos] [ i] )
{
dfs ( c, i) ;
}
}
}
} ;
6. Day24
6.1 判断是不是平衡二叉树(二叉树 + 递归)
题目链接 : JZ79 判断是不是平衡二叉树 题目描述:
解法:
算法思路:递归即可。
利用返回值,判断左右子树的高度和左右子树是否是平衡二叉树。 C++ 算法代码:
class Solution {
public :
bool IsBalanced_Solution ( TreeNode* pRoot)
{
return dfs ( pRoot) != - 1 ;
}
int dfs ( TreeNode* pRoot)
{
if ( pRoot == nullptr )
{
return 0 ;
}
int left = dfs ( pRoot-> left) ;
if ( left == - 1 )
{
return - 1 ;
}
int right = dfs ( pRoot-> right) ;
if ( right == - 1 )
{
return - 1 ;
}
return abs ( left - right) <= 1 ? max ( left, right) + 1 : - 1 ;
}
} ;
6.2 最大子矩阵(二维前缀和)
题目链接 : DP10 最大子矩阵题目描述:
解法:
算法思路:二维前缀和矩阵的应用。
初始化二维前缀和矩阵; 枚举所有的子矩阵,求出最大子矩阵。 C++ 算法代码:
# include <iostream>
using namespace std;
const int N = 105 ;
int main ( )
{
int n = 0 ;
cin >> n;
int dp[ N] [ N] = { 0 } ;
int x = 0 ;
for ( int i = 1 ; i <= n; i++ )
{
for ( int j = 1 ; j <= n; j++ )
{
cin >> x;
dp[ i] [ j] = dp[ i - 1 ] [ j] + dp[ i] [ j - 1 ] - dp[ i - 1 ] [ j - 1 ] + x;
}
}
int ret = - 128 * N;
for ( int i = 1 ; i <= n; i++ )
{
for ( int j = 1 ; j <= n; j++ )
{
for ( int x = i; x <= n; x++ )
{
for ( int y = j; y <= n; y++ )
{
ret = max ( ret, dp[ x] [ y] - dp[ i - 1 ] [ y] - dp[ x] [ j - 1 ] + dp[ i - 1 ] [ j - 1 ] ) ;
}
}
}
}
cout << ret << endl;
return 0 ;
}
6.3 小葱的01串(滑动窗口)
题目链接 : 小葱的01串 题目描述:
解法:
算法思路。滑动窗口: 长度固定的滑动窗口,因为要想符合要求,必定是⼀半⼀半的。 C++ 算法代码:
# include <iostream>
using namespace std;
int main ( )
{
int n = 0 ;
string s;
cin >> n >> s;
int sum[ 2 ] = { 0 } ;
for ( auto ch : s)
{
sum[ ch - '0' ] ++ ;
}
int left = 0 ;
int right = 0 ;
int ret = 0 ;
int half = n / 2 ;
int count[ 2 ] = { 0 } ;
while ( right < n - 1 )
{
count[ s[ right] - '0' ] ++ ;
if ( right - left + 1 > half)
{
count[ s[ left++ ] - '0' ] -- ;
}
if ( right - left + 1 == half)
{
if ( count[ 0 ] * 2 == sum[ 0 ] && count[ 1 ] * 2 == sum[ 1 ] )
{
ret += 2 ;
}
}
right++ ;
}
cout << ret << endl;
return 0 ;
}