【算法札记】练习 | Week2

目录

  • [19. 在字符串中找出连续最长的数字串(模拟 + 双指针)](#19. 在字符串中找出连续最长的数字串(模拟 + 双指针))
  • [20. 岛屿数量(BFS / DFS)​](#20. 岛屿数量(BFS / DFS))
  • [21. 拼三角(枚举 / dfs)](#21. 拼三角(枚举 / dfs))
  • [22. 求最小公倍数(数学)](#22. 求最小公倍数(数学))
  • [23. 数组中的最长连续子序列(排序 + 模拟)](#23. 数组中的最长连续子序列(排序 + 模拟))
  • [24. 字母收集(动态规划 - 路径问题)](#24. 字母收集(动态规划 - 路径问题))
  • [25. 添加逗号(模拟)​](#25. 添加逗号(模拟))
  • [26. 跳台阶(动态规划)](#26. 跳台阶(动态规划))
  • [27. 扑克牌顺子(排序)](#27. 扑克牌顺子(排序))
  • [28. 最长回文子串(回文串)​](#28. 最长回文子串(回文串))
  • [29. 买卖股票的最好时机(一)(贪心)​](#29. 买卖股票的最好时机(一)(贪心))
  • [30. 过河卒(动态规划 - 路径问题)​](#30. 过河卒(动态规划 - 路径问题))
  • [31. 游游的水果大礼包(枚举)](#31. 游游的水果大礼包(枚举))
  • [32. 买卖股票的最好时机(二)(贪心)](#32. 买卖股票的最好时机(二)(贪心))
  • [33. 倒置字符串(字符串)​](#33. 倒置字符串(字符串))
  • [34. 删除公共字符(哈希)​](#34. 删除公共字符(哈希))
  • [35. 两个链表的第一个公共结点(链表)](#35. 两个链表的第一个公共结点(链表))
  • [36. mari和shiny(动态规划 - 线性dp)​](#36. mari和shiny(动态规划 - 线性dp))

19. 在字符串中找出连续最长的数字串(模拟 + 双指针)

题目链接

遍历整个字符串,遇到数字的时候,用双指针找出这段连续的数字子串,根据此时的长度更新起始位置和长度。

cpp 复制代码
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
int main() {
    string s;
    cin >> s;
    int maxi = 0, maxlen = 0;

    int i = 0, prev = -1;
    while (i < s.size()) {
        if (isdigit(s[i])) {
            if (i - prev > maxlen) {
                maxi = prev + 1;
                maxlen = i - prev;
            }
        } else {
            prev = i;
        }
        i++;
    }
    cout << s.substr(maxi, maxlen) << endl;
    return 0;
}

20. 岛屿数量(BFS / DFS)​

题目链接

经典的 floodfill 算法。用 dfs 或者是 bfs 找出一个联通的区域,并且标记上。看看一共能找出几个联通块。

cpp 复制代码
class Solution {
  public:
    int m, n;
    bool vis[201][201];

    int solve(vector<vector<char> >& grid) {
        memset(vis, false, sizeof vis);
        m = grid.size();
        n = grid[0].size();
        int ret = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1' && !vis[i][j]) {
                    ret++;
                    bfs(grid, i, j);
                }
            }
        }
        return ret;
    }

    int dx[4] = {1, -1, 0, 0};
    int dy[4] = {0, 0, 1, -1};
    void bfs(vector<vector<char> >& grid, int i, int j) {
        queue<pair<int, int>> q;
        vis[i][j] = true;
        q.push({i, j});
        while (!q.empty()) {
            auto [a, b] = q.front();
            q.pop();
            for (int k = 0; k < 4; k++) {
                int x = a + dx[k];
                int y = b + dy[k];
                if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == '1' && !vis[x][y]) {
                    vis[x][y] = true;
                    q.push({x, y});
                }
            }
        }
    }

};

21. 拼三角(枚举 / dfs)

题目链接

因为数据量很小,这道题可以直接暴力枚举

cpp 复制代码
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
bool check(vector<int>& v)
{
    if(v[5] < v[0] + v[1] && v[4] < v[2] + v[3]
    || v[5] < v[0] + v[2] && v[4] < v[1] + v[3]
    || v[5] < v[0] + v[3] && v[4] < v[2] + v[1]
    || v[5] < v[0] + v[4] && v[3] < v[2] + v[1]
    || v[5] < v[1] + v[2] && v[4] < v[0] + v[3]
    || v[5] < v[1] + v[3] && v[4] < v[2] + v[0]
    || v[5] < v[1] + v[4] && v[3] < v[2] + v[0]
    || v[5] < v[2] + v[3] && v[4] < v[1] + v[0]
    || v[5] < v[2] + v[4] && v[3] < v[1] + v[0]
    || v[5] < v[3] + v[4] && v[2] < v[0] + v[1])
    return true;
     
    return false;
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        vector<int> v(6);
        for(int i = 0; i < 6; i++)
        {
            cin >> v[i];
        }
        sort(v.begin(), v.end());
        cout << (check(v)?"Yes":"No") << endl;
    }
    return 0;
}

22. 求最小公倍数(数学)

题目链接

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
    int a, b;
    cin >> a >> b;
    int start = min(a, b), end = a*b;
     
    for(int n = start; n <= end; n += start)
    {
        if(n % a == 0 && n % b == 0)
        {
            cout << n << endl;
            break;
        }
    }
    return 0;
}

23. 数组中的最长连续子序列(排序 + 模拟)

题目链接

一般方法是排序+模拟,时间复杂度O(nlogn)

cpp 复制代码
class Solution {
public:
    int MLS(vector<int>& arr)
    {
        sort(arr.begin(), arr.end());
        int i = 0;
        int ret = 1;
        int tmp = 1;
        while(i < arr.size()-1)
        {
            if(arr[i+1] == arr[i] + 1)
            {
                tmp++;
                ret = max(ret, tmp);
                i++;
            }
            else if(arr[i+1] == arr[i])
            {
                i++;
            }
            else
            {
                tmp = 1;
                i++;
            }
        }
        return ret;
    }
};

也可以利用并查集的思想,哈希表映射每个数和他所处连续序列的最长长度,时间复杂度O(n)完成

cpp 复制代码
class Solution 
{
public:
    int MLS(vector<int>& arr) {
        unordered_map<int, int> len;
        int ret = 0;
        for(int n : arr)
        {
            if(len.count(n) == 0)
            {
                int left = len.count(n-1)==0? 0: len[n-1];
                int right = len.count(n+1)==0? 0: len[n+1];

                int curlen = left + right + 1;
                ret = max(ret, curlen);
                len[n] = len[n-left] = len[n+right] = curlen;
            }
        }
        return ret;
    }
};

24. 字母收集(动态规划 - 路径问题)

题目链接

基础的路径问题的 dp 模型。

cpp 复制代码
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<char>> vv(n, vector<char>(m));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> vv[i][j];
        }
    }
    int hash[26];
    memset(hash, 0, sizeof hash);
    hash['l' - 'a'] = 4;
    hash['o' - 'a'] = 3;
    hash['v' - 'a'] = 2;
    hash['e' - 'a'] = 1;
    //dp[i][j]表示达到当前位置时最多分
    vector<vector<int>> dp(n, vector<int>(m));
    dp[0][0] = hash[vv[0][0] - 'a'];
    for (int i = 1; i < n; i++)

    {
        dp[i][0] = dp[i - 1][0] + hash[vv[i][0] - 'a'];
    }
    for (int j = 1; j < m; j++) {
        dp[0][j] = dp[0][j - 1] + hash[vv[0][j] - 'a'];
    }
    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]) + hash[vv[i][j] - 'a'];
        }
    }
    cout << dp[n - 1][m - 1] << endl;
    return 0;
}

25. 添加逗号(模拟)​

题目链接

从后往前遍历这个数,每提取三个数字的时候,加一个逗号。最后处理一下边界情况即可。

cpp 复制代码
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
    long long n;
    cin >> n;
    string s;
    int count = 1;
    while(n)
    {
        s += n%10+'0';
        n /= 10;
        if(count++ % 3 == 0)
        {
            s += ',';
        }
    }
    if(s.back() == ',')
    {
        s.pop_back();
    }
    reverse(s.begin(), s.end());
    cout << s << endl;
    return 0;
}

26. 跳台阶(动态规划)

题目链接

入门级的动态规划问题

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
    int n;
    cin >> n;
    int dp[41];
    dp[0] = 1, dp[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        dp[i] = dp[i-1] + dp[i-2];
    }
    cout << dp[n] << endl;
    return 0;
}

27. 扑克牌顺子(排序)

题目链接

如果能够构成顺子的话,所有的非零元素应该满足下面两个条件:

  • 不能出现重复元素;
  • max - min <= 4
cpp 复制代码
class Solution {
    bool hash[14] = { 0 };
public:
    bool IsContinuous(vector<int>& numbers) {
        int maxVal = 0, minVal = 14;
        for (auto x : numbers) {
            if (x) {
                if (hash[x]) return false;

                hash[x] = true;
                maxVal = max(maxVal, x);
                minVal = min(minVal, x);
            }
        }
        return maxVal - minVal <= 4;
    }
};

28. 最长回文子串(回文串)​

题目链接

枚举所有的中心点,然后向两边扩散。

对于每一个点,都可能有两种情况:bab或aa,需要判断两次。

cpp 复制代码
class Solution {
public:
    int getLongestPalindrome(string A)
    {
        int ret = 1;
        for(int i = 0; i < A.size(); i++)
        {
            int l = i-1, r = i+1;
            while(l >= 0 && r < A.size() && A[l] == A[r])
            {
                ret = max(ret, r-l+1);
                l--;
                r++;
            }
 
            l = i, r = i+1;
            while(l >= 0 && r < A.size() && A[l] == A[r])
            {
                ret = max(ret, r-l+1);
                l--;
                r++;
            }
        } 
        return ret;
    }
};

29. 买卖股票的最好时机(一)(贪心)​

题目链接

因为只能买卖一次,因此,对于第 i 天来说,如果在这天选择卖出股票,应该在 [0, i] 天之

内,股票最低点买入股票,此时就可以获得第 i 天的最大利润。

cpp 复制代码
#include <algorithm>
#include<iostream>
#include<vector>
using namespace std;
int main()
{
    int n;
    cin >> n;
    vector<int> p(n);
    for(int i = 0; i < n; i++)
    {
        cin >> p[i];
    }
    // dp[n]表示第n天卖股票的最大利润
    // lowp[n]表示n天前(不包括n天)的最低价格股票
    vector<int> dp(n);
    vector<int> lowp(n);
    dp[0] = 0, lowp[0] = p[0];
    for(int i = 1; i < n; i++)
    {
        lowp[i] = min(lowp[i-1], p[i-1]);
        dp[i] = p[i] - lowp[i];
    }
    cout << *max_element(dp.begin(), dp.end()) << endl;
    return 0;
}

30. 过河卒(动态规划 - 路径问题)​

题目链接

简单路径 dp 问题:相当于是有障碍物的路径类问题,标记走到障碍物上的方法数为 0 即可。

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
    int n, m, x, y;
    cin >> n >> m >> x >> y;
    n++;
    m++;
    vector<vector<bool>> horse(n, vector<bool>(m, false));
    int dx[] = {0, 1, 2, 2, 1, -1, -1, -2, -2};
    int dy[] = {0, 2, 1, -1, -2, 2, -2, 1, -1};
    for(int k = 0; k < 9; k++)
    {
        int a = x + dx[k];
        int b = y + dy[k];
        if(a >= 0 && a < n && b >= 0 && b < m)
        {
            horse[a][b] = true;
        }
    }
    //int会卡
    vector<vector<long long>> dp(n, vector<long long>(m, 0));
    if(horse[0][0])
    {
        cout << 0 << endl;
        return 0;
    }
    dp[0][0] = 1;
    for(int i = 1; i < n; i++)
    {
        dp[i][0] = horse[i][0]? 0: dp[i-1][0];
    }
    for(int j = 1; j < m; j++)
    {
        dp[0][j] = horse[0][j]? 0: dp[0][j-1];
    }
    for(int i = 1; i < n; i++)
    {
        for(int j = 1; j < m; j++)
        {
            dp[i][j] = horse[i][j]? 0: dp[i-1][j]+dp[i][j-1];
        }
    }
 
    cout << dp[n-1][m-1] << endl;
    return 0;
}

31. 游游的水果大礼包(枚举)

题目链接

很容易想到贪心,但是很不幸,贪心是错的。

正确的解法应该是枚举所有的情况。

cpp 复制代码
#include <iostream>
using namespace std;
long long n, m, a, b;
int main()
{
    cin >> n >> m >> a >> b;
    long long ret = 0;
    for(long long x = 0; x <= min(n / 2, m); x++) // 枚举 1 号礼包的个数​
    {
        long long y = min(n - x * 2, (m - x) / 2); // 计算 2 号礼包的个数​
        ret = max(ret, a * x + b * y);
    }
    cout << ret << endl;
    return 0;
}

32. 买卖股票的最好时机(二)(贪心)

题目链接

简单多状态dp

cpp 复制代码
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
    int n;
    cin >> n;
    vector<int> p(n);
    for(int i = 0; i < n; i++)
    {
        cin >> p[i];
    }
    vector<vector<int>> dp(n, vector<int>(2));
    // dp[i][0]为第i天手上没股票的最大利润, dp[i][1]为第i天手上有股票的最大利润
    dp[0][0] = 0, dp[0][1] = -p[0];
    for(int i = 1; i < n; i++)
    {
        dp[i][0] = max(dp[i-1][0], dp[i-1][1]+p[i]);
        dp[i][1] = max(dp[i-1][1], dp[i-1][0]-p[i]);
    }
    cout << max(dp[n-1][0], dp[n-1][1]) << endl;
    return 0;
}

33. 倒置字符串(字符串)​

题目链接

cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
    string ret;
    string s;
    while(cin >> s)
    {
        ret = s + ' ' + ret;
    }
    ret.pop_back();
    cout << ret << endl;
    return 0;
}

34. 删除公共字符(哈希)​

题目链接

用哈希表记录一下待删除的字符信息即可。

cpp 复制代码
#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;
int main()
{
    string s1, s2;
    getline(cin, s1);
    getline(cin, s2);
    unordered_set<char> hash;
    for(char ch : s2)
        hash.insert(ch);
 
    string ret;
    for(char ch : s1)
    {
        if(hash.count(ch) == 0)
        {
            ret += ch;
        }
    }
    cout << ret << endl;
    return 0;
}

35. 两个链表的第一个公共结点(链表)

题目链接

链表很经典的题目,让较长链表提前走两个链表长度之差步,再让两个链表同时往后走。

cpp 复制代码
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
            val(x), next(NULL) {
    }
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2)
    {
        int len1 = 0, len2 = 0;
        ListNode* cur1 = pHead1;
        ListNode* cur2 = pHead2;
        while(cur1)
        {
            len1++;
            cur1 = cur1->next;
        }
        while(cur2)
        {
            len2++;
            cur2 = cur2->next;
        }
        cur1 = pHead1;
        cur2 = pHead2;
        if(len1 > len2)
        {
            for(int i = 0; i < len1-len2; i++)
            {
                cur1 = cur1->next;
            }
        }
        else
        {
            for(int i = 0; i < len2-len1; i++)
            {
                cur2 = cur2->next;
            }
        }
 
        while(cur1 && cur2)
        {
            if(cur1 == cur2)
            {
                return cur1;
            }
            cur1 = cur1->next;
            cur2 = cur2->next;
        }
 
        return nullptr;
    }
};

36. mari和shiny(动态规划 - 线性dp)​

题目链接

简单线性 dp:​

维护 i 位置之前,一共有多少个 "s" "sh" ,然后更新 "shy" 的个数。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
int main()
{
    int n;
    cin >> n;
    string str;
    cin >> str;
    long long s = 0, sh = 0, shy = 0;
    for(char ch : str)
    {
        if(ch == 's')
        {
            s++;
        }
        else if(ch == 'h')
        {
            sh = sh + s;
        }
        else if(ch == 'y')
        {
            shy = shy + sh;
        }
    }
    cout << shy << endl;
     
    return 0;
}
相关推荐
念越2 小时前
算法每日一题 Day05|双指针解决盛最多水的容器问题
算法·力扣
RH2312112 小时前
2026.4.21Linux 共享内存
linux·服务器·网络
历程里程碑2 小时前
MySQL视图:虚拟表的实战技巧
java·开发语言·数据库·c++·sql·mysql·adb
2301_796588502 小时前
如何监控MongoDB索引碎片的产生_compact命令与碎片整理
jvm·数据库·python
eggrall2 小时前
Leetcode 最大连续 1 的个数 III(medium)
算法·leetcode·职场和发展
啊我不会诶2 小时前
Educational Codeforces Round 120 (Rated for Div. 2) vp补题
c++·算法
qq_432703662 小时前
HTML函数运行吃CPU吗_HTML函数对处理器性能影响评估【教程】
jvm·数据库·python
wanhengidc2 小时前
云主机的核心原理与架构
运维·服务器·科技·游戏·智能手机·架构
databook2 小时前
如何灵活设置公式中各个部分的颜色?
python·数学·动效
贾斯汀玛尔斯2 小时前
每天学一个算法--图算法(Graph Algorithms)
数据结构·算法