【算法札记】练习 | Week4

目录

  • [55. 小易的升级之路(数学 + 模拟)​](#55. 小易的升级之路(数学 + 模拟))
  • [56. 礼物的最大价值(动态规划 - 路径问题)](#56. 礼物的最大价值(动态规划 - 路径问题))
  • [57. 对称之美(字符串 + 哈希)​](#57. 对称之美(字符串 + 哈希))
  • [58. 经此一役小红所向无敌(模拟)​](#58. 经此一役小红所向无敌(模拟))
  • [59. 连续子数组最大和(动态规划 - 线性dp)​](#59. 连续子数组最大和(动态规划 - 线性dp))
  • [60. 非对称之美(规律)​](#60. 非对称之美(规律))
  • [61. 爱丽丝的人偶(贪心 + 构造)​](#61. 爱丽丝的人偶(贪心 + 构造))
  • [62. 集合(排序)](#62. 集合(排序))
  • [63. 最长回文子序列(动态规划 - 区间 dp)​](#63. 最长回文子序列(动态规划 - 区间 dp))
  • [64. 添加字符(字符串)](#64. 添加字符(字符串))
  • [65. 数组变换(贪心 + 位运算)](#65. 数组变换(贪心 + 位运算))
  • [66. 装箱问题(动态规划 - 01 背包)​](#66. 装箱问题(动态规划 - 01 背包))
  • [67. 打怪(模拟)](#67. 打怪(模拟))
  • [68. 字符串的分类(哈希 / 排序)](#68. 字符串的分类(哈希 / 排序))
  • [69. 城市群数量(并查集/搜索)​](#69. 城市群数量(并查集/搜索))
  • [70. 判断是不是平衡二叉树(二叉树 + 递归)​](#70. 判断是不是平衡二叉树(二叉树 + 递归))
  • [71. 最大子矩阵(二维前缀和)](#71. 最大子矩阵(二维前缀和))
  • [72. 小葱的01串(滑动窗口)​](#72. 小葱的01串(滑动窗口))

55. 小易的升级之路(数学 + 模拟)​

https://www.nowcoder.com/practice/fe6c73cb899c4fe1bdd773f8d3b42c3d?tpId=122&tqId=33649&ru=/exam/oj

根据题意模拟即可

cpp 复制代码
#include <iostream>
#include <vector>

using namespace std;
 
int gcd(int x1, int x2)
{
    if(x2 == 0) return x1;
    return gcd(x2, x1%x2);
}
 
int main()
{
    int n, a;
    while(cin >> n >> a)
    {
        while(n--)
        {
            int b;
            cin >> b;
            if(b <= a)
            {
                a += b;
            }
            else 
            {
                a += gcd(a, b);
            }
        }
        cout << a << endl;
    }
    return 0;
}

56. 礼物的最大价值(动态规划 - 路径问题)

https://www.nowcoder.com/practice/2237b401eb9347d282310fc1c3adb134?tpId=265&tqId=39288&ru=/exam/oj

简单路径类 dp 问题。

cpp 复制代码
class Solution {
public:
    int maxValue(vector<vector<int> >& grid)
    {
        int n = grid.size();
        int m = grid[0].size();
 
        vector<vector<int>> dp(n, vector<int>(m));
        dp[0][0] = grid[0][0];
        for(int i = 1; i < n; i++)
        {
            dp[i][0] = dp[i-1][0] + grid[i][0];
        }
        for(int j = 1; j < m; j++)
        {
            dp[0][j] = dp[0][j-1] + grid[0][j];
        }
        for(int i = 1; i < n; i++)
        {
            for(int j = 1; j < m; j++)
            {
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + grid[i][j];
            }
        }
        return dp[n-1][m-1];
    }
};

57. 对称之美(字符串 + 哈希)​

https://ac.nowcoder.com/acm/problem/214850

左右双指针,从第一个和最后一个字符串向中间判断,看看两个字符串中有没有相同的字符。

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
using namespace std;
 
void Fun()
{
    int n;
    cin >> n;
    vector<string> v(n);
    vector<unordered_set<char>> hash(n);
    for (int i = 0; i < n; i++)
    {
        cin >> v[i];
        for (char ch : v[i])
        {
            hash[i].insert(ch);
        }
    }
 
    for (int l = 0, r = n - 1; l < r; l++, r--)
    {
        int flag = 0;
        for (char ch : v[l])
        {
            if (hash[r].count(ch))
            {
                flag = 1;
                break;
            }
        }
        if(flag == 0)
        {
            cout << "No" << endl;
            return;
        }
    }
    cout << "Yes" << endl;
}
 
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        Fun();
    }
    return 0;
}

58. 经此一役小红所向无敌(模拟)​

https://ac.nowcoder.com/acm/problem/223985

根据题意模拟即可

cpp 复制代码
#include <iostream>
using namespace std;
 
int main()
{
    long long a, h, b, k;
    cin >> a >> h >> b >> k;
    long long ans = 0;
    while(h > 0 && k > 0)
    {
        ans += a;
        ans += b;
        h -= b;
        k -= a;
    }
    if(h > 0 && k <= 0)
    {
        ans += a * 10;
    }
    else if(h <= 0 && k > 0)
    {
        ans += b * 10;
    }
    cout << ans << endl;
    return 0;
}

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

https://www.nowcoder.com/practice/1718131e719746e9a56fb29c40cc8f95?tpId=230&tqId=39753&ru=/exam/oj

线性动态规划:

  • 状态表示:dp[i] 表示:以 i 位置为结尾的所有子数组中,最大和是多少。
  • 状态转移方程:dp[i] = max(dp[i - 1] + arr[i], arr[i])
cpp 复制代码
#include <climits>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    cin >> n;
    vector<int> nums(n);
    for(int i = 0; i < n; i++)
    {
        cin >> nums[i];
    }
    vector<long long> dp(n);
    // dp[i] 以i位置为结尾的所有子数组中,最大和是多少。

    dp[0] = nums[0];
    long long ans = dp[0];
    for(int i = 1; i < n; i++)
    {
        dp[i] = max(dp[i-1], (long long)0) + nums[i];
        ans = max(ans, dp[i]);
    }
    cout << ans << endl;
    return 0;
}

60. 非对称之美(规律)​

https://ac.nowcoder.com/acm/problem/214851

找规律:

  • 若原字符串不是回文串,则最长非回文子串的长度就是原串长度;
  • 若原字符串是回文串,再分两种情况:
    • 若所有字符都相同,则不存在非回文子串,答案为 0;
    • 若字符不全相同,则去掉首尾任一字符后,得到的长度为n-1的子串必为非回文串,答案为n-1。
cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
    string s;
    cin >> s;
    int ans = 0;
    int n = s.size();
    int flag = 1;
    for(char ch : s)
    {
        if(ch != s[0])
        {
            flag = 0;
            break;
        }
    }
    if(flag == 1)
    {
        // 原字符串全为一个字符
        cout << 0 << endl;
        return 0;
    }
    
    for(int l = 0, r = n - 1; l < r; l++, r--)
    {
        if(s[l] != s[r])
        {
            // 原字符串本身就是非回文
            cout << n << endl;
            return 0;
        }
    }
    // 原字符串是回文的
    cout << n - 1 << endl;
    return 0;
}

61. 爱丽丝的人偶(贪心 + 构造)​

https://ac.nowcoder.com/acm/problem/213471

按照"大小大小大小"的规律安排

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;
 
int main()
{
    int n;
    cin >> n;
    vector<int> v(n);
    int cur = 0;
    for(int i = 1; i <= n; i++)
    {
        v[cur] = i; 
        cur += 2;
        if(cur >= n) cur = 1;
    }
    
    for(auto i : v)
    {
        cout << i << ' ';
    }
    return 0;
}

62. 集合(排序)

https://www.nowcoder.com/practice/635ff765d4af45b5bf8e3756ed415792?tpId=134&tqId=33860&ru=/exam/oj

使用std::set即可

cpp 复制代码
#include <iostream>
#include <set>
using namespace std;
int main() 
{
    int n, m;
    cin >> n >> m;
    int x;
    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 (int x : s) 
    {
        cout << x << " ";
    }
    return 0;
}

63. 最长回文子序列(动态规划 - 区间 dp)​

https://www.nowcoder.com/practice/82297b13eebe4a0981dbfa53dfb181fa?tpId=230&tqId=39762&ru=/exam/oj

简单的子序列问题,区间dp

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
 
int main()
{
    string s;
    cin >> s;
    int n = s.size();
    vector<vector<int>> dp(n, vector<int>(n));
    // dp[i][j]表示s[i j]中的最长回文子序列
    
    for(int i = n-1; i >= 0; i--)
    {
        for(int j = i; j < n; j++)
        {
            if(i == j)
            {
                dp[i][j] = 1;
            }
            else if(i + 1 == j)
            {
                dp[i][j] = s[i] == s[j]? 2 : 1;
            }
            else
            {
                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;
}

64. 添加字符(字符串)

https://www.nowcoder.com/questionTerminal/b2b816e20e8343b49abbaf493886ce26

枚举B串中每个长度等于A串的长度,看看这两个串同一位置上不同的字符个数。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
 
int main()
{
    string s1, s2;
    cin >> s1 >> s2;
    int n = s1.size();
    int m = s2.size();
    int dis = m - n;
    int ret = 100;
    for(int i = 0; i < m-n+1; i++)
    {
        int i1 = 0, i2 = i;
        int count = 0;
        while(i1 < n)
        {
            if(s1[i1] != s2[i2])
            {
                count++;
            }
            i1++;
            i2++;
        }
        ret = min(ret, count);
    }
    cout << ret << endl;
    return 0;
}

65. 数组变换(贪心 + 位运算)

https://www.nowcoder.com/questionTerminal/c55f4f15cc3f4ff0adede7f9c69fa0c1

对于数组中的每一个数ai ,都可以表示为:

ai = k · 2t,k为奇数,t为非负整数。

那么,如果数组中的数经过若干次乘2操作后,只会改变t的大小,所以可以得出结论:如果能够变换成功,数组中的数的k值一定都相同!

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int fun(int x)
{
    while(x % 2 == 0)
        x /= 2;
    return x;
}
 
int main()
{
    int n;
    cin >> n;
    vector<int> v(n);
    for(int i = 0; i < n; i++)
    {
        cin >> v[i];
    }

    int k = fun(v[0]);
    for(int i = 1; i < n; i++)
    {
        if(k != fun(v[i]))
        {
            cout << "NO" << endl;
            return 0;
        }
    }
    cout << "YES" << endl;
    return 0;
}

66. 装箱问题(动态规划 - 01 背包)​

https://ac.nowcoder.com/acm/problem/16693

01背包问题简单应用

cpp 复制代码
#include <iostream>
using namespace std;

const int N = 35, M = 2e4 + 10;
int n, v;
int arr[N];
int dp[N][M];

int main()
{
    cin >> v >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> arr[i];
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j <= v; 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]);
            }
        }
    }
    cout << (v - dp[n][v]) << endl;
    return 0;
}

67. 打怪(模拟)

https://ac.nowcoder.com/acm/problem/202487

根据题意模拟

cpp 复制代码
#include <iostream>
using namespace std;
 
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int h, a, H, A;
        cin >> h >> a >> H >> A;
        if(a >= H)
        {
            cout << -1 << endl;
        }
        else
        {
            int ans = 0;
            // 击杀一个怪,你需要承受几次攻击
            int round = H/a + (H%a==0?0:1) - 1;
            
            while(h > round*A)
            {
                h -= round*A;
                ans++;
            }
            cout << ans << endl;
        }
    }
    return 0;
}

68. 字符串的分类(哈希 / 排序)

https://www.nowcoder.com/questionTerminal/9fbb4d95e6164cd9ab52e859fbe8f4ec

将字符串排序后,丢进能去重的哈希表里面即可。

cpp 复制代码
#include <iostream>
#include <set>
#include <string>
#include <algorithm>
using namespace std;
 
int main()
{
    int n;
    cin >> n;
    set<string> hash;
    for(int i = 0; i < n; i++)
    {
        string s;
        cin >> s;
        sort(s.begin(), s.end());
        hash.insert(s);
    }
    cout << hash.size() << endl;
    return 0;
}

69. 城市群数量(并查集/搜索)​

https://www.nowcoder.com/practice/71cde4dee669475f94d8d38832374ada?tpId=196&tqId=40411&ru=/exam/oj

floodfill问题,这道题可以用bfs/dfs/并查集解决。

搜索:

cpp 复制代码
class Solution {
public: 
    bool vis[200];
    int n;
    int citys(vector<vector<int> >& m) 
    {
        n = m.size();
        memset(vis, 0, sizeof vis);
        int ret = 0;
        for(int i = 0; i < n; i++)
        {
            if(!vis[i])
            {
                ret++;
                //bfs(m, i);
                dfs(m, i);
            }
        }
        return ret;
    }

    void bfs(vector<vector<int>>& m, int pos)
    {
        queue<int> q;
        q.push(pos);
        vis[pos] = true;
        while(!q.empty())
        {
            int i = q.front();
            q.pop();
            for(int j = 0; j < n; j++)
            {
                if(m[i][j] == 1 && !vis[j])
                {
                    vis[j] = true;
                    q.push(j);
                }
            }
        }
    }

    void dfs(vector<vector<int>>& m, int pos)
    {
        vis[pos] = true;
        for(int j = 0; j < n; j++)
        {
            if(m[pos][j] == 1 && !vis[j])
            {
                dfs(m, j);
            } 
        }
    }
};

并查集:

cpp 复制代码
class Solution {
public:
    int citys(vector<vector<int> >& m)
    {
        int n = m.size();
        vector<int> v(n, -1);
        // 如果v[i]为负,表示这个下标是根,绝对值是节点数量
        // 如果v[i]不为负,v[i]是i的父亲下标
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(m[i][j] == 1)
                {
                    int root1 = i, root2 = j;
                    while(v[root1] >= 0)
                    {
                        root1 = v[root1];
                    }
                    while(v[root2] >= 0)
                    {
                        root2 = v[root2];
                    }
                    if(root1 != root2)
                    {
                        v[root1] += v[root2];
                        v[root2] = root1;
                    }
                     
                }
            }
        }
        
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            if(v[i] < 0)
            {
                ans++;
            }
        }
        return ans;

    }
};

70. 判断是不是平衡二叉树(二叉树 + 递归)​

https://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId=13&tqId=11192&ru=/exam/oj

递归计算即可

cpp 复制代码
/**
 * 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)
    {
        if(pRoot == nullptr)
        {
            return true;
        }
        int left = Height(pRoot->left);
        int right = Height(pRoot->right);
        return IsBalanced_Solution(pRoot->left) && IsBalanced_Solution(pRoot->right) && abs(left-right) <= 1;
    }
 
    int Height(TreeNode* root)
    {
        if(root == nullptr)
        {
            return 0;
        }
        return 1 + max(Height(root->left), Height(root->right));
    }
 
};

71. 最大子矩阵(二维前缀和)

https://www.nowcoder.com/practice/a5a0b05f0505406ca837a3a76a5419b3?tpId=230&tqId=40416&ru=/exam/oj

二维前缀和矩阵的应用。

  • 初始化二维前缀和矩阵;
  • 枚举所有的子矩阵,找出最大子矩阵。
cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
 
int main()
{
    int n;
    cin >> n;
    vector<vector<int>> nums(n+1, vector<int>(n+1,0));
    for(int i = 1; i < n+1; i++)
    {
        for(int j = 1; j < n+1; j++)
        {
            cin >> nums[i][j];
        }
    }
    auto dp = nums;
    int ans = -128;
 
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + nums[i][j];
            ans = max(ans, dp[i][j]);
        }
    }
 
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            for(int ii = i; ii <= n; ii++)
            {
                for(int jj = j; jj <= n; jj++)
                {
                    ans = max(ans, dp[ii][jj]-dp[i-1][jj]-dp[ii][j-1]+dp[i-1][j-1]);
                }
            }
        }
    }
    
    cout << ans << endl;
    return 0;
}

72. 小葱的01串(滑动窗口)​

https://ac.nowcoder.com/acm/problem/230830

长度固定为原串长度一半的滑动窗口,因为要想符合要求,必定是一半一半的。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
int main()
{
    int n;
    cin >> n;
    string s;
    cin >> s;
    int num1 = 0, num0 = 0;
    for(char ch : s)
    {
        if(ch == '1')
            num1++;
        else
            num0++;
    }
    
    int ans = 0;
    int cur1 = 0, cur0 = 0;
    int l = 0, r = 0;
    while(cur0 + cur1 < n/2 - 1)
    {
        if(s[r] == '1')
            cur1++;
        else
            cur0++;
        r++;
    }
 
    while(r < n)
    {
        if(s[r] == '1')
            cur1++;
        else
            cur0++;
    
        if(cur1 * 2 == num1 && cur0 * 2 == num0)
            ans++;
        
        if(s[l] == '1')
            cur1--;
        else
            cur0--;
        
        r++;
        l++;
    }
 
    l = n/2 + 1, r = 0;
    while(r < n/2 - 1)
    {
        if(s[r] == '1')
            cur1++;
        else
            cur0++;
    
        if(cur1 * 2 == num1 && cur0 * 2 == num0)
            ans++;
        
        if(s[l] == '1')
            cur1--;
        else
            cur0--;
    
        r++;
        l++;
    }
 
    cout << ans << endl;
    return 0;
}
相关推荐
goodesocket3 小时前
芯片HAST测试:通电工作下如何精准模拟极端环境挑战?
c++
Mortalbreeze3 小时前
深度理解文件系统 ---- 从磁盘存储到内核存储
大数据·linux·数据库
英辰朗迪AI获客3 小时前
【AI】豆包与抖音智能功能深度评测报告
人工智能
大橙子打游戏3 小时前
难题彻底解决!VPaste:让 SSH 终端也能"粘贴"截图
人工智能
特种加菲猫3 小时前
从零开始手撕AVL树:详解插入、平衡因子更新与四种旋转
开发语言·c++
萑澈3 小时前
算法竞赛入门:C++ STL核心用法与时空复杂度速查手册
数据结构·c++·算法·stl
IT_陈寒4 小时前
Redis内存用爆了,原来我们都忽略了这个配置
前端·人工智能·后端
сокол4 小时前
【网安-Web渗透测试-内网渗透】域环境权限维持
服务器·windows·网络安全·系统安全
captain_AIouo4 小时前
降本增效突围,Captain AI助力Ozon商家提升盈利空间
大数据·人工智能·经验分享·aigc