算法部分
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 :
这批矿产的检验结果 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.
- 明天晚上打一下力扣双周赛 报名戳这里