笔试强训——第二周

25_7_13

第二题:岛屿数量_牛客题霸_牛客网

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 判断岛屿数量
     * @param grid char字符型vector<vector<>> 
     * @return int整型
     */
    int n = 0, m = 0;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    bool vis[201][201] = {false};
    int solve(vector<vector<char> >& grid) 
    {
        n = grid.size(), m = grid[0].size();
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < m; j++)
            {
                if(grid[i][j] == '1' && !vis[i][j])
                {
                    ans++;
                    bfs(i, j, grid);
                }
            }
        }
        return ans;
    }
    void bfs(int i, int j, vector<vector<char> >& grid)
    {
        queue<pair<int, int>> myq;
        myq.push({i, j});
        vis[i][j] = true;
        while(!myq.empty())
        {
            auto [a, b] = myq.front();
            myq.pop();
            for(int k = 0; k < 4; k++)
            {
                int x = a + dx[k], y = b + dy[k];
                if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && grid[x][y] == '1')
                {
                    myq.push({x, y});
                    vis[x][y] = true;
                }
            }
        }
    }
};

第三题:拼三角

先排升序,之后若是前面三个中前两个加起来不大于第三个并且后三个中也是如此,那么就没有能组成两个三角形的;因为前三个中的第三个在枚举时一直变大,而前两个本来加起来不足第三个现在更新不足了;后面三个的前两个在枚举时一直变小,而第三个不变,同理不行

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main()
{
    int t = 0;
    cin >> t;
    while(t--)
    {
        vector<int> arr(6, 0);
        for(int i = 0; i < arr.size(); i++)
            cin >> arr[i];
        sort(arr.begin(), arr.end());
        if((arr[0] + arr[1] > arr[2] && arr[3] + arr[4] > arr[5]) || 
           (arr[0] + arr[2] > arr[3] && arr[1] + arr[4] > arr[5]) ||
           (arr[0] + arr[3] > arr[4] && arr[1] + arr[2] > arr[5]) ||
           (arr[0] + arr[4] > arr[5] && arr[1] + arr[2] > arr[3]))
        {
            cout << "Yes" << endl;
        }
        else
            cout << "No" << endl;
    }
    return 0;
}

25_7_14

第三题:字母收集_牛客题霸_牛客网

动态规划

#include <iostream>
#include<vector>
using namespace std;

//动态规划
int main() 
{
    int a = 0, b = 0;
    cin >> a >> b;
    vector<vector<char>> num1(a, vector<char>(b, 'a'));
    for(int i = 0; i < a; i++)
        for(int j = 0; j < b; j++)
            cin >> num1[i][j];
    vector<int> num2(26, 0);
    num2['l' - 97] = 4;
    num2['o' - 97] = 3;
    num2['v' - 97] = 2;
    num2['e' - 97] = 1;
    
    vector<vector<int>> dp(a+1, vector<int>(b+1, 0));//避免判断下标是否有效
    dp[1][1] = num2[num1[0][0] - 97];
    for(int i = 1; i <= a; i++)
        for(int j = 1; j <= b; j++)
        {
            int cur = num2[num1[i-1][j-1] - 97];
            dp[i][j] = max(dp[i][j-1]+cur, dp[i-1][j]+cur);   
        }
    cout << dp[a][b];
    return 0;      
}

25_7_15

第三题:扑克牌顺子_牛客题霸_牛客网

解法一:先找出非0元素并且统计非0元素的个数,之后排序这些非0元素,遍历这些非0元素若是有相同的直接返回false,若是两个元素之间存在缺失的统计缺失的数字,最后和0元素个数相比,若是小于则返回true说明可以用0来补齐,反之返回false

class Solution {
public:
    bool IsContinuous(vector<int>& numbers) {
        if (numbers.size() != 5) return false;
        
        // 统计0的个数
        int zeroCount = 0;
        for (int num : numbers) {
            if (num == 0) zeroCount++;
        }
        
        // 对非零数字进行排序
        vector<int> nonZero;
        for (int num : numbers) {
            if (num != 0) nonZero.push_back(num);
        }
        sort(nonZero.begin(), nonZero.end());
        
        // 检查非零数字是否有重复
        for (int i = 0; i < nonZero.size() - 1; i++) {
            if (nonZero[i] == nonZero[i + 1]) return false;
        }
        
        // 计算非零数字之间的间隔总和
        int gap = 0;
        for (int i = 0; i < nonZero.size() - 1; i++) {
            gap += nonZero[i + 1] - nonZero[i] - 1;
        }
        
        // 如果间隔总和小于等于0的个数,则可以组成顺子
        return gap <= zeroCount;
    }
};

解法二:(五个数要是顺子)是(无重复非0元素并且非0元素的最大值减去最小值<=4)的充要条件

class Solution {
public:
    bool IsContinuous(vector<int>& numbers) 
    {
        //标记有无重复元素出现
        vector<bool> hash(14, false);
        int Maxval = 0, Minval = 14;
        for(auto i : numbers)
        {
            if(i)
            {
                if(hash[i]) return false;
                hash[i] = true;
                //更新最大元素与最小元素
                Maxval = max(i, Maxval);
                Minval = min(i, Minval);
            }
        }
        return (Maxval - Minval) <= 4;
    }
};

25_7_16

第二题:买卖股票的最好时机(一)_牛客题霸_牛客网

//贪心算法
//从前往后固定卖出的点,计算出该点前面包括当前点最小的买入点(买卖可在同一天)
//当固定卖出的点后移遍历时,用一个变量记录上一次卖出时的买入最小点,此时再计算时,只需要取出这个变量和当前固定卖出的点较小值就是当前需要的最小买入点
//要从前往后否则计算出较小值时间复杂度高,还麻烦

#include <iostream>
#include <iterator>
#include<vector>
using namespace std;

int main() 
{
    int n = 0;
    cin >> n;
    vector<int> nums(n, 0);
    for(int i = 0; i < n; i++)
        cin >> nums[i];
    int prevMin = nums[0];//记录前面最小点
    int ans = 0;
    for(int i = 1; i < n; i++)//i遍历的是卖出的点
    {
        prevMin = min(prevMin, nums[i]);
        ans = max(ans, nums[i] - prevMin);
    }   
    cout << ans;
    return 0;
}

第三题:[NOIP2002 普及组] 过河卒_牛客题霸_牛客网

//动态规划+路径问题
//每一个位置的可达路径条数等于其左、上位置可达路径条数相加
//但是当这个位置是马可以到达的位置时,此位置的可达条数为零
//状态转移方程为dp[i][j] = dp[i-1][j] + dp[i][j-1]或者0
//初始状态:因为题中为n+1,m+1,要将第一行一列的初始化,就要新加一行
//所以dp开为n+2,m+2,为了保证dp[1][1]的位置是1(也就是原来的A(0,0))
//要将dp[0][1]或者dp[1][0]的位置初始化为1

#include <iostream>
#include<vector>
using namespace std;

int main() 
{
    int n, m, x, y;
    cin >> n >> m >> x >> y;
    vector<vector<long long>> dp(n+2, vector<long long>(m+2, 0));
    dp[0][1] = 1;
    for(int i = 1; i < n + 2; i++)
    {
        for(int j = 1; j < m + 2; j++)
        {
            if((i == x + 1 && j == y + 1) ||
                (abs(i - x - 1) + abs(j - y - 1) == 3 && i != x + 1 && j != y + 1))
                dp[i][j] = 0; 
            else
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        }
    }
    cout << dp[n + 1][m + 1];
    return 0;
}

25_7_17

第一题:游游的水果大礼包

类似于ax+by这种二元函数求值的问题一般都是枚举解决

本题不能直接断言哪个礼包价值大就一直选那个礼包,举反例可知。应该枚举,从选0个一号礼包到选能选的最大数量的一号礼包中选出总价值最大的一个

#include<iostream>
using namespace std;

typedef long long LL;

int main()
{
    LL n = 0, m = 0, a = 0, b = 0;
    cin >> n >> m >> a >> b;
    //先统计全选一号礼包能有多少一号礼包,之后枚举从0个1号礼包到最多个1号礼包,得出最大价值
    LL one_top = min(n / 2, m);
    LL ans = 0;
    for(int i = 0; i <= one_top; i++)
    {
        LL b1 = n, b2 = m, tmp_ans = 0;
        b1 -= i * 2;//除去一号礼包之后的水果个数
        b2 -= i;
        
        //一号礼包价值
        tmp_ans += i * a;
        
        //二号礼包个数以及价值
        LL two_num = min(b1, b2 / 2);
        tmp_ans += two_num * b;
        
        //更新结果
        ans = max(ans, tmp_ans);
    }
    cout << ans << endl;
    return 0;
}

第二题:买卖股票的最好时机(二)_牛客题霸_牛客网

贪心算法:

计算每段上升价格的最大与最小之差,之后加起来全部的

或者每两天就计算一次,后一天比前一天大就相加它们的差

#include <iostream>
#include<vector>
using namespace std;

int main() 
{
    int n = 0;
    cin >> n;
    vector<int> prices(n, 0);
    for(int i = 0; i < n; i++)
        cin >> prices[i];
    long long ans = 0;
    // //贪心算法:只需要找到一段上升部分,用其最大减去最小price,最后相加所有的
    // int left = 0, right = 1;
    // while(right < n)
    // {
    //     if(prices[right] >= prices[right - 1])
    //     {
    //         ++right;
    //     } 
    //     else 
    //     {
    //         ans += prices[right - 1] - prices[left];
    //         left = right;
    //         ++right;
    //     }
    // }
    // ans += prices[right - 1] - prices[left];
    

    //解法二继续贪心
    //现在前后挨着的两天进行判断,后一天比前一天大就加到结果中,因为交易次数不限制
    for(int i = 1; i < n; i++)
    {
        if(prices[i] > prices[i - 1])
            ans += prices[i] - prices[i - 1];
    }
    cout << ans << endl;
    return 0;
}

25_7_18

第三题:mari和shiny

多状态的线性动态规划

s[i]、sh[i]、shy[i]分别表示这个位置及其之前的s的数量、sh的数量、shy的数量 ;

状态转移方程:

s[i] = s[i - 1] (i位置不是's')或者 1 + s[i - 1](i位置是's')

sh[i] = sh[i - 1](i位置不是'h')或者 sh[i - 1] + s[i - 1](i位置是'h')

shy[i] = shy[i - 1](i位置不是'y')或者 shy[i] = shy[i - 1] + sh[i - 1](i位置是'y')

这样最后返回shy[n - 1]就可以找到结果

#include<iostream>
#include<vector>
using namespace std;

typedef long long LL;
int main()
{
    int n = 0;
    cin >> n;
    string str;
    cin  >> str;
    
    LL ans = 0;
    vector<LL> s(n, 0);
    vector<LL> sh(n, 0);
    vector<LL> shy(n, 0);
    s[0] = str[0] == 's' ? 1 : 0;
    
    for(int i = 1; i < n; i++)
    {
        if(str[i] == 's')
            s[i] = 1 + s[i - 1];
        else
            s[i] = s[i - 1];
    }
    
    for(int i = 1; i < n; i++)
    {
        if(str[i] == 'h')
            sh[i] = s[i - 1] + sh[i - 1];
        else
            sh[i] = sh[i - 1];
    }
    
    for(int i = 1; i < n; i++)
    {
        if(str[i] == 'y')
            shy[i] = sh[i - 1] + shy [i - 1];
        else
            shy[i] = shy[i - 1];
    }
    
    cout << shy[n - 1];
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值