数大雁和IPv4地址转换成整数[E卷-hw_od]

1.数大雁
题目描述
一群大雁往南飞,给定一个字符串记录地面上的游客听到的大雁叫声,请给出叫声最少由几只大雁发出。
具体的:
1.大雁发出的完整叫声为”quack“,因为有多只大雁同一时间嘎嘎作响,所以字符串中可能会混合多个”quack”。
2.大雁会依次完整发出”quack”,即字符串中’q’ ,‘u’, ‘a’, ‘c’, ‘k’ 这5个字母按顺序完整存在才能计数为一只大雁。如果不完整或者没有按顺序则不予计数。
3.如果字符串不是由’q’, ‘u’, ‘a’, ‘c’, ‘k’ 字符组合而成,或者没有找到一只大雁,请返回-1。
输入描述
一个字符串,包含大雁quack的叫声。1 <= 字符串长度 <= 1000,字符串中的字符只有’q’, ‘u’, ‘a’, ‘c’, ‘k’。
输出描述
大雁的数量
示例1
输入: quackquack 输出:1
示例2
输入:qaauucqcaa 输出:-1
示例3
输入:quacqkuackquack 输出:2
示例4
输出:qququaauqccauqkkcauqqkcauuqkcaaukccakkck  输出:5
示例5
输出:quacqkuquacqkacuqkackuack  输出:3

#include<bits/stdc++.h>
using namespace std;
const string quack="quack";
int solve(string& s){
    vector<int> count(5);
    int res=0;
    for(int i=0;i<s.size();i++){
        int idx=quack.find(s[i]);
        if(idx==0){
            count[0]++; 
        }else{
            if(count[idx-1]==0){
                return -1;
            }
            count[idx-1]--;
            count[idx]++;
        }
        if(idx==4) count[4]--;
        int num=accumulate(count.begin(),count.end(),0);
        res=max(res,num);
    }
    int a=accumulate(count.begin(),count.end(),0);
    if(a>0) return -1;
    return res;
}
int main(){
    string s;
    cin>>s;
    int res=solve(s);
    cout<<res<<endl;
    return 0;
}

思路:其实就是简单的模拟,但是要想清楚, 一个大雁的完整叫声是"quack", 当我们在遍历字符串s的时候, 只要遇到字符'q', 很有可能就是一只新大雁.
但是我们在观察实例3, quacqkuack.... 在第一个quack中穿插了一个q, 我们可以肯定这是一只新的大雁的叫声, 
对比实例1, quackquack, 第一个quack中没有穿插q, 所以最少一只大雁就能完成叫声
还有就是, 当我们枚举到'u'这个字符的时候, 就要去找前面还有没有q(用一个数组进行维护), 如果没有直接return -1;

1.字符有效性检查:在循环中,检查每个字符是否属于“quack”中的字符,否则直接返回-1。
2.阶段转移:处理每个字符时,如果是'q'则开始新的大雁,否则检查前一阶段是否有大雁,如果有则转移到大雁到当前阶段。
3.完成处理:当处理到'k'时,减少第四阶段的计数,表示该大雁已完成叫声。
4.活跃大雁数目:每次处理完一个字符后,计算当前所有阶段的大雁总数,并更新最大值。
5.最终检查:处理完所有字符后,检查所有阶段的计数总和是否为0,如果不为0,表示有未完成的大雁,返回-1。否则返回最大活跃大雁数目。

2.IPv4地址转换成整数
题目描述
存在一种虚拟IPv4地址,由4小节组成,每节的范围为0~255,以#号间隔,虚拟IPv4地址可以转换为一个32位的整数,例如:
128#0#255#255,转换为32位整数的结果为2147549183(0x8000FFFF)
1#0#0#0,转换为32位整数的结果为16777216(0x01000000)
现以字符串形式给出一个虚拟IPv4地址,限制第1小节的范围为1-128,即每一节范围分别为(1-128)#(0-255)#(0-255)#(0-255),要求每个IPv4地址只能对应到唯一的整数上。如果是非法IPv4,返回invalid IP
输出描述
输出一行,按照要求输出整型。不合法的IP地址输出invalid IP。
示例1
输入: 100#101#1#5  输出: 1684340997
示例2
输入: 1#2#3 输出: invalid IP

#include<bits/stdc++.h>
#include <cctype>
#include <sstream>
using namespace std;
bool solve(string& str,int minVal,int maxVal){
    if(str.empty()||(str.size()>1&&str[0]=='0')){
        return false;
    }
    for(char c:str){
        if(!isdigit(c)){
            return false;
        }
    }
    int num=stoi(str);
    if(num>=minVal&&num<=maxVal){
        return true;
    }
    return false;
}
int main(){
    string str;
    cin>>str;
    stringstream ss(str);
    string str1;
    vector<string> a;
    while(getline(ss,str1,'#')){
        a.push_back(str1);
    }
    /*
    getline函数的作用是从输入流 ss 中读取字符,直到遇到分隔符 #(或者输入流结束),并将读取的内容存储到字符串 
    str 中。每次调用 getline 时,str 的内容会被清空,然后存储新的读取内容
    */
    if(a.size()<4){
        cout<<"invalid IP"<<endl; return 0;
    }
    //检查一下范围
    vector<int> b;
    for(int i=0;i<4;i++){
        int minVal;
        if(i==0){
            minVal=1;
        }else{
            minVal=0;
        }
        int maxVal;
        if(i==0){
            maxVal=128;
        }else{
            maxVal=255;
        }
        if(solve(a[i],minVal,maxVal)){
            b.push_back(stoi(a[i]));
        }else{
            cout<<"invalid IP"<<endl;
            return 0;
        }  
    }
    unsigned int num=(b[0]<<24|b[1]<<16|b[2]<<8|b[3]);
    cout<<num<<endl;
    return 0;
}
思路: 还是模拟题意,将输入的字符串s分割按'#'进行分割, 每个分割出的数字判断是否在题目指定的范围中, 如果是在指定范围内的数字, 就按照从左到右填充32位二进制数
eg:128#0#255#255
1.将128放在最高位(第32位到第25位):
  128的二进制表示为10000000,所以最高位的8位是10000000。
2.将0放在次高位(第24位到第17位):
0的二进制表示为00000000,所以次高位的8位是00000000。
3.将255放在次低位(第16位到第9位):
255的二进制表示为11111111,所以次低位的8位是11111111。
4.将255放在最低位(第8位到第1位):
255的二进制表示为11111111,所以最低位的8位是11111111。
最后, 将这4个字节的二进制值组合起来,得到32位整数的二进制表示:
10000000 00000000 11111111 11111111
接下来,我们将这个二进制数转换为十进制数(权重乘积和), 
所以,128#0#255#255转换为32位整数的结果是2147549183
转换成代码的话, 可以<<后进行|操作即可
最后,为了保证左移的稳定性和防止int溢出, 我们采用了unsigned int

后续我也会提供其他的代码版本, 关于HUAWEI OD-E卷的题, 我会持续更新3个月, 每天两道题, 希望自己能坚持下来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值