寒假CS每日打卡 Feb.5th


算法部分

1.Acwing 入门组每日一题
题目:ISBN号码

每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字、1位识别码和3位分隔符,其规定格式如“x-xxx-xxxxx-x”,其中符号“-”是分隔符(键盘上的减号),最后一位是识别码,例如0-670-82162-4就是一个标准的ISBN码。
ISBN码的首位数字表示书籍的出版语言,例如0代表英语;第一个分隔符“-”之后的三位数字代表出版社,例如670代表维京出版社;第二个分隔之后的五位数字代表该书在出版社的编号;最后一位为识别码。 
识别码的计算方法如下:
首位数字乘以1加上次位数字乘以2…以此类推,用所得的结果mod 11,所得的余数即为识别码,如果余数为10,则识别码为大写字母X。
例如ISBN号码0-670-82162-4中的识别码4是这样得到的:对067082162这9个数字,从左至右,分别乘以1,2,…,9,再求和,即0×1+6×2+…+2×9=158,然后取158 mod 11的结果4作为识别码。 
你的任务是编写程序判断输入的ISBN号码中识别码是否正确,如果正确,则仅输出“Right”;如果错误,则输出你认为是正确的ISBN号码。

输入格式
输入文件只有一行,是一个字符序列,表示一本书的ISBN号码(保证输入符合ISBN号码的格式要求)。

输出格式
输出文件共一行,假如输入的ISBN号码的识别码正确,那么输出“Right”,否则,按照规定的格式,输出正确的ISBN号码(包括分隔符“-”)。

输入样例:
0-670-82162-4
输出样例:
Right
输入样例:
0-670-82162-0
输出样例:
0-670-82162-4

题解:
  简单的字符串模拟题目。

代码:

#include <iostream>
#include <string>

using namespace std;

int main(){
    string s;
    int tmp = 0;

    cin >> s;
    for(int i = 0, j = 1; i < s.length() - 1; i ++){
        if(s[i] == '-')
            continue;
           //计算总和
        tmp += j * (s[i] - '0');
        j ++;
    }
	//得到识别码
    tmp %= 11;
    if(tmp == s[s.length() - 1] - '0' || (tmp == 10 && s[s.length() - 1] == 'X'))
        cout << "Right" << endl;
    else{
        if(tmp == 10)
            s[s.length() - 1] = 'X';
        else
            s[s.length() - 1] = tmp + '0';
        cout << s << endl;
    }
    return 0;
}

2.Acwing 提高组每日一题
题目:聪明的质监员

小 T 是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有 n 个矿石,从 1 到 n 逐一编号,每个矿石都有自己的重量 wi 以及价值 vi。
检验矿产的流程是: 
1、给定 m 个区间[Li,Ri]; 
2、选出一个参数 W; 
3、对于一个区间[Li,Ri],计算矿石在这个区间上的检验值 Yi : 
QQ截图20190314005531.png
这批矿产的检验结果 Y 为各个区间的检验值之和。
即:Y = Y1+Y2+…+Ym
若这批矿产的检验结果与所给标准值 S 相差太多,就需要再去检验另一批矿产。
小 T 不想费时间去检验另一批矿产,所以他想通过调整参数 W 的值,让检验结果尽可能的靠近标准值 S,即使得 S-Y 的绝对值最小。
请你帮忙求出这个最小值。

输入格式
第一行包含三个整数 n,m,S,分别表示矿石的个数、区间的个数和标准值。 
接下来的 n 行,每行 2 个整数,中间用空格隔开,第 i+1 行表示 i 号矿石的重量 wi 和价值 vi 。 
接下来的 m 行,表示区间,每行 2 个整数,中间用空格隔开,第 i+n+1 行表示区间[Li, Ri]的两个端点 Li 和 Ri。
注意:不同区间可能重合或相互重叠。

输出格式
输出一个整数,表示所求的最小值。

数据范围
1≤n,m≤200000,
0<wi,vi≤106,
0<S≤1012,
1≤Li≤Ri≤n

题解:
  一道数学题,暂时还没做出来。

3.LeetCode 每日一题
题目:尽可能使字符串相等

给你两个长度相同的字符串,s 和 t。
将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。
用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。
如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。
如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0。

示例 1:
输入:s = “abcd”, t = “bcdf”, cost = 3
输出:3
解释:s 中的 “abc” 可以变为 “bcd”。开销为 3,所以最大长度为 3。

示例 2:
输入:s = “abcd”, t = “cdef”, cost = 3
输出:1
解释:s 中的任一字符要想变成 t 中对应的字符,其开销都是 2。因此,最大长度为 1。

示例 3:
输入:s = “abcd”, t = “acde”, cost = 0
输出:1
解释:你无法作出任何改动,所以最大长度为 1。

提示:
1 <= s.length, t.length <= 10^5
0 <= maxCost <= 10^6
s 和 t 都只含小写英文字母。

题解:
  双指针题目,当费用没超过时,扩大区间,否则缩小区间,使得算法复杂度降低到O(n)。

代码:

class Solution {
public:
    int equalSubstring(string s, string t, int maxCost) {
        int tmp = 0, ans = 0, le = 0;

        for(int i = 0; i < s.length(); i ++){
            tmp += abs(s[i] - t[i]);
            //注意这里为什么使用if 而不是 while , 还有为什么不需要每次取max,最后直接返回的值就是最大值呢
            if(tmp > maxCost){
                tmp -= abs(s[le] - t[le]);
                ++ le;
            }
        }
        //左指针到区间末端的数目就是最大字符个数
        return (int)s.length() - le;
    }
};

4.无重复字符的最长子串
题目:

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。

示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

示例 4:
输入: s = “”
输出: 0

提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成

题解:
  还是巧用双指针,当右指针遇到的字符 c 出现次数超过1,则右移左指针,直到 c 出现的次数为1 。

代码:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
    	//记录字符出现的次数
        unordered_map<char, int> map;
        int le = 0, ri = 0, ans = 0;

        while(ri < s.length()){
            map[s[ri]] ++;
            //出现不止一次,则移动左指针,直到只出现一次为止
            while(map[s[ri]] > 1){
                map[s[le ++]] --;
            }
            //更新最大值
            ans = max(ans, ri - le + 1);
            ++ ri;
        }
        return ans;
    }
};

5.翻转二叉树以匹配先序遍历
题目:

给定一个有 N 个节点的二叉树,每个节点都有一个不同于其他节点且处于 {1, …, N} 中的值。
通过交换节点的左子节点和右子节点,可以翻转该二叉树中的节点。
考虑从根节点开始的先序遍历报告的 N 值序列。将这一 N 值序列称为树的行程。
(回想一下,节点的先序遍历意味着我们报告当前节点的值,然后先序遍历左子节点,再先序遍历右子节点。)
我们的目标是翻转最少的树中节点,以便树的行程与给定的行程 voyage 相匹配。
如果可以,则返回翻转的所有节点的值的列表。你可以按任何顺序返回答案。
如果不能,则返回列表 [-1]。

示例 1:
在这里插入图片描述
输入:root = [1,2], voyage = [2,1]
输出:[-1]

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

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

提示:
1 <= N <= 100

题解:
  考虑到前序遍历,我们只需要按照顺序递归去处理即可。

代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> flipMatchVoyage(TreeNode* root, vector<int>& voyage) {
        vector<int> ans;
        int pos = 0;

        if(dfs(root, voyage, ans, pos))
            return ans;
        else
            return {-1};
    }

    bool dfs(TreeNode *root, vector<int> &voyage, vector<int> &ans, int &pos){
        if(root == nullptr)
            return true;

        if(root -> val != voyage[pos])
            return false;
       
        ++ pos;
        if(dfs(root -> left, voyage, ans, pos) && dfs(root -> right, voyage, ans, pos))
            return true;
        //一旦不相等就只可能是在该节点反转,数据保证节点值不同所以无需回溯
        ans.push_back(root -> val);
        return dfs(root -> right, voyage, ans, pos) && dfs(root -> left, voyage, ans, pos);
    }
};

6.验证 IP 地址
题目:

编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。
如果是有效的 IPv4 地址,返回 “IPv4” ;
如果是有效的 IPv6 地址,返回 “IPv6” ;
如果不是上述类型的 IP 地址,返回 “Neither” 。
IPv4 地址由十进制数和点来表示,每个地址包含 4 个十进制数,其范围为 0 - 255, 用(".")分割。比如,172.16.254.1;
同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。
IPv6 地址由 8 组 16 进制的数字来表示,每组表示 16 比特。这些组数字通过 (":")分割。比如, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。
然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (:😃 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。
同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。

示例 1:
输入:IP = “172.16.254.1”
输出:“IPv4”
解释:有效的 IPv4 地址,返回 “IPv4”

示例 2:
输入:IP = “2001:0db8:85a3:0:0:8A2E:0370:7334”
输出:“IPv6”
解释:有效的 IPv6 地址,返回 “IPv6”

示例 3:
输入:IP = “256.256.256.256”
输出:“Neither”
解释:既不是 IPv4 地址,又不是 IPv6 地址

示例 4:
输入:IP = “2001:0db8:85a3:0:0:8A2E:0370:7334:”
输出:“Neither”

示例 5:
输入:IP = “1e1.4.5.6”
输出:“Neither”

提示:
IP 仅由英文字母,数字,字符 ‘.’ 和 ‘:’ 组成。

题解:
  字符串处理题目不难,但是繁琐,一次想ac很难,基本上wa了之后看错在哪里,然后改善代码。

代码:

class Solution {
public:
    string validIPAddress(string IP) {
        vector<string> arr;
        //分别记录. 以及 : 是否出现
        bool op1 = false, op2 = false;
        int pre = 0;
        for(int i = 0; i < IP.length(); i ++){
            if(IP[i] == '.' || IP[i] == ':'){
            	//将输入分割为字符串数组
                arr.push_back(IP.substr(pre, i - pre));
                pre = i + 1;
                if(IP[i] == '.')
                    op1 = true;
                else if(IP[i] == ':')
                    op2 = true;
            }
        }
        arr.push_back(IP.substr(pre));
		// . 和 : 都出现肯定不合法
        if(op1 && op2)
            return "Neither";
        if(op1 && check1(arr))
            return "IPv4";
        if(op2 && check2(arr))
            return "IPv6";
        return "Neither";
    }

    bool check1(vector<string> &arr){
    	//ipv4 只有4段
        if(arr.size() != 4)
            return false;
        for(string &s : arr){
       		//是空串或者长度大于3或者有多余0
            if(s == "" || s.length() > 3 || (s[0] == '0' && s.length() > 1))
                return false;
            int tmp = 0;
            for(int i = 0; i < s.length(); i ++){
            	//字符不是数字
                if(s[i] < '0' || s[i] > '9')
                    return false;
                tmp = tmp * 10 + s[i] - '0';
            }
            //总和大于255
            if(tmp > 255)
                return false;
        }
        return true;
    }

    bool check2(vector<string> &arr){
    	//ipv6只有8段
        if(arr.size() != 8 )
            return false;
        for(string &s : arr){
        	//空串或者长度大于4
            if(s.length() > 4 || s.empty())
                return false;
            for(char c : s){
                c = toupper(c);
                //不是有效字符
                if(!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')))
                    return false;
            }
        }
        return true;
    }
};

书籍部分

无(今天出去玩了 hhhh)


PS.

  1. 明天晚上打一下力扣双周赛 报名戳这里
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值