寒假CS每日打卡 Feb.4th


算法部分

1.Acwing 入门组每日一题
题目:a^b
求 a 的 b 次方对 p 取模的值。

输入格式
三个整数 a,b,p ,在同一行用空格隔开。

输出格式
输出一个整数,表示a^b mod p的值。

数据范围
0≤a,b≤109
1≤p≤109
输入样例:
3 2 7
输出样例:
2

题解:
  快速幂,较简单,大家可以拓展一下,尝试一下这道题矩阵快速幂

代码:

#include <iostream>

using namespace std;

int main(){
    
    
    long long a, b, p, ans = 1;

    cin >> a >> b >> p;
    while(b){
    
    
        if(b & 1)
            ans = (ans * a) % p;
        a= (a * a) % p;
        b >>= 1;
    }
    cout << ans % p << endl;
    return 0;
}

2.Acwing 提高组每日一题
题目:耍杂技的牛

农民约翰的N头奶牛(编号为1…N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。奶牛们不是非常有创意,只提出了一个杂技表演:叠罗汉,表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。这N头奶牛中的每一头都有着自己的重量Wi以及自己的强壮程度Si。一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。
您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能的小。

输入格式
第一行输入整数N,表示奶牛数量。
接下来N行,每行输入两个整数,表示牛的重量和强壮程度,第i行表示第i头牛的重量Wi以及它的强壮程度Si。

输出格式
输出一个整数,表示最大风险值的最小可能值。

数据范围
1≤N≤50000,
1≤Wi≤10,000,
1≤Si≤1,000,000,000
输入样例:
3
10 3
2 5
3 3
输出样例:
2
题解:
  需要理解题意,然后思考证明,假设第 i 和第 i + 1 头牛需要排序,无论这两头牛如何排序,其之前的牛(1 到 i - 1)的重量和是一定的,所以当 w(i + 1) - si [第i头牛排在下面] < wi - s(i + 1) [第 i + 1 头牛排在下面] 时,di头牛需要排在下面,移项得到 w(i + 1) + s(i + 1) < wi + si,所以和越大的牛排得越后。

代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int MAXN = 5e4 + 10;
typedef pair<int, int> PII;
PII arr[MAXN];

int main(){
    
    
    int n, sum = 0, ans = -1e6;

    cin >> n;

    for(int i = 0; i < n; i ++)
        cin >> arr[i].first >> arr[i].second;
	//按照s + w从小到大排序
    sort(arr, arr + n, [](PII &a, PII &b){
    
    
            return a.first + a.second < b.first + b.second;
    });

    for(int i = 0; i < n; i ++){
    
    
    	//更新风险最大值
        ans = max(ans, sum - arr[i].second);
        //更新从第一头牛到当前的重量和
        sum += arr[i].first;
    }
    cout << ans << endl;
    return 0;
}

3.LeetCode 每日一题
题目:子数组最大平均数 I

给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数。

示例:
输入:[1,12,-5,-6,50,3], k = 4
输出:12.75
解释:最大平均数 (12-5-6+50)/4 = 51/4 = 12.75

提示:
1 <= k <= n <= 30,000。
所给数据范围 [-10,000,10,000]。

题解:
  简单的双指针题目。

代码:

class Solution {
    
    
public:
    double findMaxAverage(vector<int>& nums, int k) {
    
    
        double ans = -1e6;
        int tmp = 0, le = 0;

        while(le < k - 1)
            tmp += nums[le ++];

        while(le < nums.size()){
    
    
        	//尾指针移动
            tmp += nums[le ++];
            ans = max(ans, (double) tmp / k);
            //头指针移动
            tmp -= nums[le - k];
        }
        return ans;
    }
};

4.均分纸牌
题目:

有N堆纸牌,编号分别为 1,2,…,N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若干张纸牌,然后移动。移牌规则为:在编号为 1 的堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N−1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。例如 N=4,4 堆纸牌数分别为:(9,8,17,6)。移动 3 次可达到目的:
从第三堆取四张牌放入第四堆,各堆纸牌数量变为:(9,8,13,10)。
从第三堆取三张牌放入第二堆,各堆纸牌数量变为:(9,11,10,10)。
从第二堆取一张牌放入第一堆,各堆纸牌数量变为:(10,10,10,10)。

输入格式
第一行包含整数 N。
第二行包含 N 个整数,A1,A2,…,AN 表示各堆的纸牌数量。

输出格式
输出使得所有堆的纸牌数量都相等所需的最少移动次数。

数据范围
1≤N≤100,
1≤Ai≤10000

输入样例:
4
9 8 17 6
输出样例:
3
题解:
  注意每次只能从相邻牌堆移动纸牌,所以不管如何移动纸牌,只能依次从相邻的牌堆移动,从左往右依次考虑,如果当前堆的牌不够就去和右边借,牌多了就给右边。

代码:

#include <iostream>

using namespace std;

const int MAXN = 110;
int arr[MAXN];

int main(){
    
    
    int n, sum = 0, ans = 0;
    
    cin >> n;
    
    for(int i = 0; i < n; i ++)
        cin >> arr[i], sum += arr[i];
    //计算纸牌均值
    sum /= n;
    for(int i = 0; i < n; i ++){
    
    
        if(arr[i] != sum)
        	//向右边牌堆移动纸牌
            ++ ans, arr[i + 1] += arr[i] - sum;
    }
    cout << ans << endl;
    return 0;
}

5.春招冲刺-最大矩形
题目:

给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例 1:
在这里插入图片描述
输入:matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]]
输出:6
解释:最大矩形如上图所示。

提示:
rows == matrix.length
cols == matrix[0].length
0 <= row, cols <= 200
matrix[i][j] 为 ‘0’ 或 ‘1’

题解:
  这题还是蛮不错了,将一个O(n4)的问题优化到了O(n3),典型的空间换时间做法,做法不难,很值得去学习。前两层for循环矩阵的右下角坐标,最后一层for循环矩阵的宽,然后矩阵的长度可以和矩阵的宽一起更新,具体做法是预处理一个二维数组记录(i, j)位置左边连续1的个数。

代码:

class Solution {
    
    
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
    
    
        if(matrix.empty())
            return 0;

        int n = matrix.size(), m = matrix[0].size(), ans = 0;
        vector<vector<int>> sum(n, vector<int>(m, 0));

        //预处理,依次得到该位置同行左边的连续1的个数
        for(int i = 0; i < n; i ++){
    
    
            for(int j = 0; j < m; j ++){
    
    
            	//第0列
                if(!j)
                    sum[i][j] = matrix[i][j] - '0';
                else
                	//当前为0则为0,为1就是右边的1个数 + 1
                    sum[i][j] = matrix[i][j] - '0' ? sum[i][j - 1] + 1 : 0;
            }
        }
		//枚举矩阵右下角的行
        for(int i = 0; i < n; i ++){
    
    
        	//枚举矩阵左下角的列
            for(int j = 0; j < m; j ++){
    
    
                int tmp = INT_MAX;
                //从第i行到第0行
                for(int k = i; k >= 0; k --){
    
    
                	//tmp存储矩阵行方向最大的1个数,为矩阵的长
                    tmp = min(tmp, sum[k][j]);
                    //长 乘 宽 更新ans,宽就是i到k的差值
                    ans = max(ans, (i - k + 1) * tmp);
                }
            }
        }
        return ans;
    }
};

6.春招冲刺-相同的树
题目:

你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:
在这里插入图片描述
输入:p = [1,2,3], q = [1,2,3]
输出:true

示例 2:
在这里插入图片描述
输入:p = [1,2], q = [1,null,2]
输出:false

提示:
两棵树上的节点数目都在范围 [0, 100] 内
-104 <= Node.val <= 104

题解:
  一道精巧的小题,练练dfs。

代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    
    
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
    
    
    	//当p或者q有一个是nullptr
        if(!p || !q){
    
    
        	//两者有一个不是nullptr,此时肯定为false,因为树都不同构
            if(p || q)
                return false;
            return true;
        }
        //值不相等,false
        if(p -> val != q -> val)
            return false;
           //递归查询左子树和右子树
        return isSameTree(p -> left, q -> left) && isSameTree(p -> right, q -> right);
    }
};

7.春招冲刺-大礼包
题目:

在LeetCode商店中, 有许多在售的物品。然而,也有一些大礼包,每个大礼包以优惠的价格捆绑销售一组物品。现给定每个物品的价格,每个大礼包包含物品的清单,以及待购物品清单。请输出确切完成待购清单的最低花费。每个大礼包的由一个数组中的一组数据描述,最后一个数字代表大礼包的价格,其他数字分别表示内含的其他种类物品的数量。任意大礼包可无限次购买。

示例 1:
输入: [2,5], [[3,0,5],[1,2,10]], [3,2]
输出: 14
解释:
有A和B两种物品,价格分别为¥2和¥5。
大礼包1,你可以以¥5的价格购买3A和0B。
大礼包2, 你可以以¥10的价格购买1A和2B。
你需要购买3个A和2个B, 所以你付了¥10购买了1A和2B(大礼包2),以及¥4购买2A。

示例 2:
输入: [2,3,4], [[1,1,0,4],[2,2,1,9]], [1,2,1]
输出: 11
解释:
A,B,C的价格分别为¥2,¥3,¥4.
你可以用¥4购买1A和1B,也可以用¥9购买2A,2B和1C。
你需要买1A,2B和1C,所以你付了¥4买了1A和1B(大礼包1),以及¥3购买1B, ¥4购买1C。
你不可以购买超出待购清单的物品,尽管购买大礼包2更加便宜。

说明:
最多6种物品, 100种大礼包。
每种物品,你最多只需要购买6个。
你不可以购买超出待购清单的物品,即使更便宜。

题解:
  经典的dfs回溯题目,这里不多解释了,见代码。

代码:

class Solution {
    
    
public:
	//最低廉的价格
    int ans = INT_MAX;

    int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {
    
    
        dfs(price, special, needs, 0);
        return ans;
    }

    void dfs(vector<int>& price, vector<vector<int>>& special, vector<int>& needs, int money){
    
    
        //用来判断每样东西是否都买了
        int tmp = 0;
        for(int i = 0; i < needs.size(); i ++){
    
    
        	//多买了,不是正解,return
            if(needs[i] < 0)
                return;
            tmp += needs[i];
        }
        //tmp == 0,东西买全了
        if(!tmp){
    
    
            ans = min(ans, money);
            return;
        }
        //尝试每一种大礼包
        for(vector<int> &tmp : special){
    
    
            for(int i = 0; i < needs.size(); i ++)
                needs[i] -= tmp[i];
            dfs(price, special, needs, money + tmp[tmp.size() - 1]);
            //回溯
            for(int i = 0; i < needs.size(); i ++)
                needs[i] += tmp[i];
        }
        //不买大礼包,全部单买
        for(int i = 0; i < needs.size(); i ++)
            money += price[i] * needs[i];
        ans = min(ans, money);
    }
};

书籍部分

MYSQL必知必会 第13 - 15章 ✔


PS.

  1. 明天复习一下矩阵快速幂
  2. 看TCP/IP 书

猜你喜欢

转载自blog.csdn.net/Raymond_YP/article/details/113664114