【算法札记】练习 | Week1

目录

  • [1. 数字统计(数学+模拟)](#1. 数字统计(数学+模拟))
  • [2. 两个数组的交集(哈希)](#2. 两个数组的交集(哈希))
  • [3. 点击消除(栈)](#3. 点击消除(栈))
  • [4. 牛牛的快递(模拟)](#4. 牛牛的快递(模拟))
  • [5. 最小花费爬楼梯(动态规划-线性dp)](#5. 最小花费爬楼梯(动态规划-线性dp))
  • [6. 数组中两个字符串的最小距离(模拟+贪心)](#6. 数组中两个字符串的最小距离(模拟+贪心))
  • [7. 简写单词(模拟)](#7. 简写单词(模拟))
  • [8. dd爱框框(滑动窗口)](#8. dd爱框框(滑动窗口))
  • [9. 除2!(贪心+堆)](#9. 除2!(贪心+堆))
  • [10. Fibonacci数列(斐波那契数列)](#10. Fibonacci数列(斐波那契数列))
  • [11. 单词搜索(搜索)](#11. 单词搜索(搜索))
  • [12. 杨辉三角(动态规划)​](#12. 杨辉三角(动态规划))
  • [13. 游游的you(贪心 + 模拟)](#13. 游游的you(贪心 + 模拟))
  • [14. 腐烂的苹果(多源 BFS)](#14. 腐烂的苹果(多源 BFS))
  • [15. 孩子们的游戏(约瑟夫问题)](#15. 孩子们的游戏(约瑟夫问题))
  • [16. 大数加法(高精度加法)](#16. 大数加法(高精度加法))
  • [17. 链表相加(二)(链表 + 高精度加法)](#17. 链表相加(二)(链表 + 高精度加法))
  • [18. 大数乘法(高精度乘法)](#18. 大数乘法(高精度乘法))

1. 数字统计(数学+模拟)

题目链接

开胃小菜,依次枚举区间内的每个数,每个数判断每一位是否为2,对每个数不断%10,/10。

cpp 复制代码
#include <iostream>
using namespace std;
int main() 
{
    int l, r;
    cin >> l >> r;
    int ret = 0;
    for (int i = l; i <= r; i++) 
    {
        int tmp = i;
        while (tmp) 
        {

            if (tmp % 10 == 2) 
                ret++;
            tmp /= 10;
        }
    }
    cout << ret << endl;
    return 0;
}

2. 两个数组的交集(哈希)

题目链接

遍历第一个数组,将其中⼀个数组丢进哈希表中;

遍历另⼀个数组的时候,在哈希表中看看是否存在,存在则属于交集。

cpp 复制代码
class Solution {
  public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> ret;
        unordered_map<int, bool> hash;
        for (auto x : nums1) {
            hash[x] = true;
        }
        for (auto x : nums2) {

            if (hash[x]) {
                ret.push_back(x);
                hash[x] = false;
            }
        }
        return ret;
    }
};

3. 点击消除(栈)

题目链接

思路:用栈来模拟消除的过程

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
int main() {
    string s, st;
    cin >> s;
    for (auto ch : s) {
        if (st.size() && st.back() == ch) st.pop_back();
        else st += ch;
    }
    cout << (st.size() == 0 ? "0" : st) << endl;
    return 0;
}

4. 牛牛的快递(模拟)

题目链接

很简单,按照题意模拟即可。
补充一个知识点,在math.h中有两个库函数ceil和floor,能对浮点数进行向上取整、向下取整。

cpp 复制代码
#include <iostream>
#include <cmath>
using namespace std;
int main() {
    float a;
    char b;
    cin >> a >> b;
    int ret = 0;
    if (a <= 1) {
        ret += 20;
    } else {
        ret += 20;
        a -= 1;
        ret += ceil(a);
    }
    if (b == 'y') ret += 5;
    cout << ret << endl;
    return 0;
}

5. 最小花费爬楼梯(动态规划-线性dp)

题目链接

简单的dp,dp[i]表示从头到达i位置台阶的最小花费。当n==1或2时,你也至少需要跨一个台阶。

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

int main()
{
    int n;
    cin >> n;
    vector<int> cost(n);
    for(int i = 0; i < n; i++)
    {
        cin >> cost[i];
    }
    if(n == 1)
    {
        cout << cost[0] << endl;
        return 0;
    }
    if(n == 2)
    {
        cout << min(cost[0], cost[1]) << endl;
        return 0;
    }
    vector<int> dp(n+1);
    dp[0] = dp[1] = 0;
    for(int i = 2; i <= n; i++)
    {
        dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]);
    }

    cout << dp[n] << endl;
    return 0;
}

6. 数组中两个字符串的最小距离(模拟+贪心)

题目链接

用两个变量分别记录两个字符串最近一次出现的位置,每次判断距离是否更小。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;
int main() 
{
    int n;
    cin >> n;
    string s1, s2;
    cin >> s1 >> s2;
    int i1 = -1, i2 = -1;
    int ret = 1000000;
    for (int i = 0; i < n; i++) 
    {
        string s;
        cin >> s;
        if (s == s1) 
        {
            if (i2 != -1) 
            {
                ret = min(ret, i - i2);
            }
            i1 = i;
        }
        else if (s == s2) 
        {
            if (i1 != -1) 
            {
                ret = min(ret, i - i1);
            }
            i2 = i;
        }
    }
    cout << ((ret == 1000000) ? -1 : ret) << endl;

    return 0;
}

7. 简写单词(模拟)

题目链接

最简单的一集,不说了。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
int main() {
    string s;
    while (cin >> s) { 
        if (s[0] <= 'z' && s[0] >= 'a') cout << (char)(s[0] - 32);
        else cout << s[0];
    }
    return 0;
}

8. dd爱框框(滑动窗口)

题目链接

基础的滑动窗口题型

cpp 复制代码
#include <iostream>
using namespace std;
const int N = 1e7+10;
int arr[N];
int n, x;
int main()
{
    cin >> n >> x;
    for(int i = 1; i <= n; i++) cin >> arr[i];
    int left = 0, right = 0, sum = 0;
    int retLen = N, retLeft = -1, retRight = -1;
    while(right <= n)
    {
        sum += arr[right];
        while(sum >= x)
    {
    if(right - left + 1 < retLen)
    {
        retLeft = left;
        retRight = right;
        retLen = right - left + 1;
    }
    sum -= arr[left++];
    }
        right++;
    }
    cout << retLeft << " " << retRight << endl;
    return 0;
}

9. 除2!(贪心+堆)

题目链接

贪心策略很好想,每次取当前最大的偶数 /= 2,用堆来维护。直到没有偶数或次数用完。

cpp 复制代码
#include <iostream>
#include <queue>
using namespace std;
typedef long long LL;
LL n, k;
priority_queue<LL> heap;
int main()
{
    cin >> n >> k;
    LL sum = 0, x;
    while(n--)
    {
        cin >> x;
        sum += x;
        if(x % 2 == 0) heap.push(x);
    }
    while(heap.size() && k--)
    {
        LL t = heap.top() / 2;
        heap.pop();
        sum -= t;
        if(t % 2 == 0) heap.push(t);
    }
    cout << sum << endl;
    return 0;
}

10. Fibonacci数列(斐波那契数列)

题目链接

求斐波那契数列的过程中,判断一下:何时 n 会在两个斐波那契数之间,再判断那边距离更小即可。

cpp 复制代码
#include <iostream>
using namespace std;
int n;
int main() {
    cin >> n;
    int a = 0, b = 1, c = 1;
    while (n > c) {
        a = b;
        b = c;
        c = a + b;
    }
    cout << min(c - n, n - b) << endl;
    return 0;
}

11. 单词搜索(搜索)

题目链接

一个简单的深度优先搜索题型。

cpp 复制代码
class Solution {
  public:
    int n;
    int m;
    bool vis[101][101];
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    string _word;

    bool exist(vector<string>& board, string word) {
        n = board.size();
        m = board[0].size();
        _word = word;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (board[i][j] == word[0] && dfs(board, i, j, 0))
                    return true;
            }
        }
        return false;
    }

    bool dfs(vector<string>& board, int i, int j, int pos) {
        if (pos == _word.size() - 1) return true;

        vis[i][j] = true;
        for (int k = 0; k < 4; k++) {
            int a = i + dx[k];
            int b = j + dy[k];

            if (a >= 0 && a < n && b >= 0 && b < m && board[a][b] == _word[pos + 1] && !vis[a][b]) {
                if (dfs(board, a, b, pos + 1))
                    return true;
            }
        }
        vis[i][j] = false;
        return false;
    }
};

12. 杨辉三角(动态规划)​

题目链接

简单的动态规划。

cpp 复制代码
#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
    int n;
    cin >> n;
    vector<vector<int>> dp(n, vector<int>(n));
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j <= i; j++)
        {
            if(j == 0 || j == i) dp[i][j] = 1;
            else dp[i][j] = dp[i-1][j]+dp[i-1][j-1];
 
            printf("%5d", dp[i][j]);
        }
        printf("\n");
    }
     
    return 0;
}

13. 游游的you(贪心 + 模拟)

题目链接

显然 you 和 oo 两个字符串不可能有字符重叠部分,但是 you 的分值更高,因此我们应该优先去拼凑 you,然后再考虑 oo。

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
    int q;
    cin >> q;
    while(q--)
    {   
        int a, b, c;
        cin >> a >> b >> c;
        int ans = 0;
        int min_of_y_u = min(a, c);
        int num_of_o = b;
        if(min_of_y_u >= num_of_o)
        {
            ans += 2*num_of_o;
        }
        else
        {
            ans += 2*min_of_y_u;
            num_of_o -= min_of_y_u;
            ans += num_of_o-1;
        }
        cout << ans << endl;
    }
    return 0;
}

14. 腐烂的苹果(多源 BFS)

题目链接

这道题目是多源BFS问题。但是第一次做这道题时,笔者还没有学到这种题型,而只会BFS最短路问题。于是依此为基础,我去掉了一般的bool visited数组,而加入了一个time数组记录每个好苹果最短的腐烂时间,每次取更小时间填入。

cpp 复制代码
class Solution
{
public:
    int n;
    int m;
    int time[1001][1001] = {0};
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
 
    int rotApple(vector<vector<int>>& grid)
    {
        n = grid.size();
        m = grid[0].size();
        int ret = 0;
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < m; j++)
            {
                if(grid[i][j] == 2)
                    bfs(grid, i, j);
            }
        }
 
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < m; j++)
            {
                if(grid[i][j] == 1 && time[i][j] == 0)
                {
                    return -1;
                }
 
                ret = max(time[i][j], ret);
            }
        }
        return ret;
    }
     
    void bfs(vector<vector<int>>& grid, int i, int j)
    {
        int cur_time = 0;
        queue<pair<int, int>> q;
        q.push({i, j});
        time[i][j] = 0;

        int size = 0;
        while(!q.empty())
        {
            size = q.size();
            auto [a, b] = q.front();
            q.pop();
            cur_time = time[a][b];
            for(int k = 0; k < 4; k++)
            {
                int x = a + dx[k];
                int y = b + dy[k];
                if(x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 1 && (time[x][y]==0 || time[x][y] > cur_time))
                {
                    q.push({x, y});
                    time[x][y] = cur_time + 1;
                }
            }
        }
         
    }
 
};

15. 孩子们的游戏(约瑟夫问题)

题目链接

经典的约瑟夫问题,用动态规划来解决,dp[i] 表示 i 个人玩游戏最后剩下的人的下标(从0开始)。
递推公式:dp[i] = (dp[i-1] + m) % i

递推的本质:当从 i-1 个人扩展到 i 个人时,新加入的人在下标0位置,原来的索引都向后移动 m 位,所以要在原结果上加 m 再对 i 取模。

环形队列模拟当然也能完成这种题目,不过时间复杂度略逊一筹。

cpp 复制代码
class Solution {
public:
    int LastRemaining_Solution(int n, int m) 
    {
        int f = 0; // f初始相当于dp[1];
        for(int i = 2; i <= n; i++)
            f = (f + m) % i;

        return f;
    }
};

16. 大数加法(高精度加法)

题目链接

模拟加法列竖式运算的过程即可,每次记录进位。

cpp 复制代码
class Solution {
  public:
    string solve(string s, string t) {
        string ret;
        int flag = 0;
        int i = s.size() - 1, j = t.size() - 1;
        while (i >= 0 || j >= 0) {
            int tmp = flag;
            if (i >= 0) tmp += s[i--] - '0';
            if (j >= 0) tmp += t[j--] - '0';

            if (tmp >= 10) {
                tmp %= 10;
                flag = 1;
            } else {
                flag = 0;
            }
            ret += tmp + '0';
        }
        if (flag == 1) {
            ret += '1';
        }
        reverse(ret.begin(), ret.end());
        return ret;
    }
};

17. 链表相加(二)(链表 + 高精度加法)

题目链接

模拟高精度加法的过程,只不过是在链表中进行而已。先将链表逆序,这样从头到尾相加就是从低位到高位的过程,最后再逆序结果链表。

cpp 复制代码
/**
 * struct ListNode {
 *  int val;
 *  struct ListNode *next;
 *  ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
  public:
    ListNode* revList(ListNode* head) {
        if (head == nullptr || head->next == nullptr) return head;

        ListNode* cur1 = head;
        ListNode* cur2 = head->next;
        ListNode* newhead = revList(cur2);
        cur2->next = cur1;
        cur1->next = nullptr;
        return newhead;
    }

    ListNode* addInList(ListNode* head1, ListNode* head2) {
        head1 = revList(head1);
        head2 = revList(head2);

        ListNode* newhead = new ListNode(0);
        ListNode* cur1 = head1, *cur2 = head2;
        ListNode* cur = newhead;

        int flag = 0;
        while (cur1 || cur2) {
            int tmp = flag;
            if (cur1) {
                tmp += cur1->val;
                cur1 = cur1->next;
            }
            if (cur2) {
                tmp += cur2->val;
                cur2 = cur2->next;
            }
            if (tmp >= 10) {
                tmp %= 10;
                flag = 1;
            } else {
                flag = 0;
            }
            ListNode* node = new ListNode(tmp);
            cur->next = node;
            cur = cur->next;
        }
        if (flag) {
            ListNode* node = new ListNode(flag);
            cur->next = node;
        }

        newhead->next = revList(newhead->next);

        return newhead->next;
    }
};

18. 大数乘法(高精度乘法)

题目链接

根据列竖式运算的过程模拟即可。

但是我们可以改进一下列竖式的过程:

  • 先计算无进位相乘并且相加后的结果;
  • 然后再处理进位。
cpp 复制代码
class Solution {
  public:
    string solve(string s, string t) {
        if (s == "0" || t == "0") return "0";

        reverse(s.begin(), s.end());
        reverse(t.begin(), t.end());

        int n = s.size(), m = t.size();
        int i = 0, j = 0;

        vector<int> tmp(m + n - 1);

        for (i = 0; i < n; i++) {
            for (j = 0; j < m; j++) {
                tmp[i + j] += (s[i] - '0') * (t[j] - '0');
            }
        }

        int flag = 0;
        string ret;
        for (i = 0; i < tmp.size(); i++) {
            int t = flag;
            t += tmp[i];
            if (t >= 10) {
                flag = t / 10;
                t %= 10;
            } else {
                flag = 0;
            }
            ret += '0' + t;
        }
        while (flag) {
            ret += '0' + flag % 10;
            flag /= 10;
        }
        reverse(ret.begin(), ret.end());
        return ret;
    }
};
相关推荐
踏着七彩祥云的小丑2 小时前
Python——排序
开发语言·python
计算机徐师兄2 小时前
Python基于深度学习的图片智能分类系统(附源码,文档说明)
python·深度学习·图片智能分类系统·python图片智能分类系统·汽车分类·汽车图片智能分类系统·python汽车智能分类系统
sp_fyf_20242 小时前
【大语言模型】 是什么在驱动表示层操控?——关于操控模型拒绝机制的案例研究
人工智能·深度学习·机器学习·语言模型·自然语言处理
c++圈来了个新人2 小时前
C++类和对象(上)
c语言·开发语言·数据结构·c++·考研
人道领域2 小时前
【LeetCode刷题日记】15.三数之和(梦破碎的地方)
算法·leetcode·面试
fpcc2 小时前
并行编程实战——CUDA编程的图之六子图的创建
人工智能·cuda
Godspeed Zhao2 小时前
具身智能中的传感器技术23——六维力/力矩传感器1
人工智能·科技·具身智能
️是782 小时前
信息奥赛一本通(4005:【GESP2306一级】时间规划)
数据结构·c++·算法
tankeven2 小时前
HJ174 交换到最大
c++·算法