笔试强训题(4)

1. Day19

1.1 小易的升级之路(数学 + 模拟)

  1. 题目链接WY3 小易的升级之路
  2. 题目描述:

  1. 解法:
    • 算法思路:根据题意模拟即可。
  2. 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 礼物的最大价值(动态规划 - 路径问题)

  1. 题目链接JZ47 礼物的最大价值
  2. 题目描述:

  1. 解法:
    • 算法思路:简单路径类 dp 问题。
  2. 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 对称之美(字符串 + 哈希)

  1. 题目链接对称之美
  2. 题目描述:

  1. 解法:
    • 算法思路:左右指针判断回⽂串。判断左右指针相等的时候,应该看看两个字符串中有没有相同的字符。
  2. 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 经此⼀役小红所向无敌(模拟)

  1. 题目链接经此⼀役小红所向无敌
  2. 题目描述:

  1. 解法:
    • 算法思路:根据数据直接计算出结果。
  2. 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);
    
    // 2. 计算剩余⾎量
    h -= n * b;
    k -= n * a;
    
    // 3. 判断是否都还活着
    if(h > 0 && k > 0)
    {
        h -= b;
        k -= a;
        ret += a + b;
    }

    // 4. 判断是否会放⼤
    if(h > 0 || k > 0)
    {
        ret += 10 * (h > 0 ? a : b);
    }
    
    cout << ret << endl;
    
    return 0;
}

2.2 连续子数组最大和(动态规划 - 线性dp)

  1. 题目链接DP6 连续子数组最大和
  2. 题目描述:

  1. 解法:
    • 算法思路。简单线性 dp。
      • 状态表示: dp[i] 表示:以 i 位置为结尾的所有⼦数组中,最⼤和是多少。
      • 状态转移方程: dp[i] = max(dp[i - 1] + arr[i], arr[i])
  2. 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 非对称之美(规律)

  1. 题目链接非对称之美
  2. 题目描述:

  1. 解法:
    • 算法思路:找到规律就很好做了。
  2. 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 爱丽丝的人偶(贪心 + 构造)

  1. 题目链接爱丽丝的人偶
  2. 题目描述:

  1. 解法:
    • 算法思路:放个小的之后,再放个大的~
  2. 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 集合(排序)

  1. 题目链接JD7 集合
  2. 题目描述:

  1. 解法:
    • 算法思路:什么?笔试题?我直接 set 走起!
  2. 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)

  1. 题目链接DP22 最长回文子序列
  2. 题目描述:

  1. 解法:
    • 算法思路。基础的区间 dp 问题:
      1. 状态表示:
        • dp[i][j] 表示:字符串 [i, j] 范围内的最长回文子序列的长度;
      2. 状态转移方程:
        • 当 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]);
    1. 返回值: dp[0][n - 1] 。
  2. 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 添加字符(字符串)

  1. 题目链接[编程题]添加字符
  2. 题目描述:

  1. 解法:
    • 算法思路:枚举所有字符串 a 与字符串 b 相对应的位置。
  2. 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 = m - 1; j >= 0; j--)  // 后面添加字符串
        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 数组变换(贪心 + 位运算)

  1. 题目链接[编程题]数组变换
  2. 题目描述:

  1. 解法:
    • 算法思路:如果能够变换成功,那么最大的数除以剩下的数的商,⼀定都是 2 的 n 次方。
  2. 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;
            }
        }

        // if(b % arr[i])
        // {
        //     return false;
        // }

        // int x = b / arr[i];
        // if(x - (x & -x))
        // {
        //     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 背包)

  1. 题目链接[NOIP2001]装箱问题
  2. 题目描述:

  1. 解法:
    • 算法思路:01 背包简单应用。
  2. 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[N][M] = {0};
    int dp[M] = {0};
    for(int i = 1; i <= n; i++)
    {
        // for(int j = 0; j <= v; j++)
        for(int j = v; j >= arr[i]; j--)
        {
//             dp[i][j] = dp[i - 1][j];
//             if(j >= arr[i])
//             {
//                 dp[i][j] = max(dp[i][j], dp[i - 1][j - arr[i]] + arr[i]);
//             }
            
            dp[j] = max(dp[j], dp[j - arr[i]] + arr[i]);
        }
    }
    
    // cout << v - dp[n][v] << endl;
    cout << v - dp[v] << endl;
    
    return 0;
}

5. Day23

5.1 打怪(模拟)

  1. 题目链接打怪
  2. 题目描述:

  1. 解法:
    算法思路:根据题意模拟,注意⼀下细节就好了。
  2. C++ 算法代码:
#include <iostream>
using namespace std;

int h,a,H,A;

int check()
{
// 循环一步步解决
//     if(a >= H)
//     {
//         return -1;
//     }
    
//     int ret = 0;
//     while(h > 0)
//     {
//         for(int i = H; i > 0; )
//         {
//             i -= a;
            
//             if(i <= 0)
//             {
//                 continue;
//             }
            
//             h -= A;
//             if(h <= 0)
//             {
//                 return ret;
//             }
//         }
        
//         ret++;
//     }
    
//     return ret;

// 整体计算 
    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 字符串的分类(哈希 / 排序)

  1. 题目链接[编程题]字符串分类
  2. 题目描述:

  1. 解法:
    • 算法思路:将字符串排序后,丢进能去重的哈希表里面就好了。
  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 城市群数量(联通块)

  1. 题目链接NC345 城市群数量
  2. 题目描述:

  1. 解法:
    • 算法思路:经典 floodfill 算法,可以用 dfs 或者 bfs 解决。
  2. 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 判断是不是平衡二叉树(二叉树 + 递归)

  1. 题目链接JZ79 判断是不是平衡二叉树
  2. 题目描述:

  1. 解法:
    • 算法思路:递归即可。
      • 利用返回值,判断左右子树的高度和左右子树是否是平衡二叉树。
  2. C++ 算法代码:
/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
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 最大子矩阵(二维前缀和)

  1. 题目链接: DP10 最大子矩阵
  2. 题目描述:

  1. 解法:
    • 算法思路:二维前缀和矩阵的应用。
      • 初始化二维前缀和矩阵;
      • 枚举所有的子矩阵,求出最大子矩阵。
  2. 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串(滑动窗口)

  1. 题目链接小葱的01串
  2. 题目描述:

  1. 解法:
    • 算法思路。滑动窗口:
    • 长度固定的滑动窗口,因为要想符合要求,必定是⼀半⼀半的。
  2. C++ 算法代码:
#include <iostream>
using namespace std;

int main()
{
    int n = 0;
    string s;
    cin >> n >> s;
    
    int sum[2] = { 0 };    // 统计字符串中所有 0 和 1 的个数
    for(auto ch : s)
    {
        sum[ch - '0']++;
    }
    
    int left = 0;
    int right = 0;
    int ret = 0;
    int half = n / 2;
    int count[2] = { 0 }; // 统计窗⼝内 0 和 1 的个数
    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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Smile丶凉轩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值