【刷题】华为机考训练(至21题)

牛客网链接

1.计算字符串最后一个单词的长度

计算字符串最后一个单词的长度,单词以空格隔开。
解法:str[-1]str.split()

str = input().strip().split()
print(len(str[len(str)-1]))
str = input().split()
print(len(str[-1]) if len(str)>1 else len(str[0]))
in_str = str(input("请输入:"))
if len(in_str)==0 or len(in_str)>=5000:
    return print("非空,长度小于5000")
else:
    return print(len(in_str.split()[-1]))

2.计算字符个数

写出一个程序,接受一个由字母和数字组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数。不区分大小写。
⚠️range()中的参数要为整型,所以要转型。如果不转,那么里面参数为字符串类型,会报:TypeError: ‘str’ object cannot be interpreted as an integer

a=input().lower()
b=input().lower()
print(a.count(b))

3.明明的随机数

明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作(同一个测试用例里可能会有多组数据,希望大家能正确处理)。
注:测试用例保证输入参数的正确性,答题者无需验证。测试用例不止一组。
样例输入解释:
样例有两组测试
第一组是3个数字,分别是:2,2,1。
第二组是11个数字,分别是:10,20,40,32,67,40,20,89,300,400,15。
解法一:列表
⚠️处理多组输入用while

while True:
    try:
        n=int(input())
        r=[]
        for i in range(n):
            r.append(int(input()))
        for i in sorted(set(r)):
            print(i)
    except:
        break

解法二:集合

while True:
    try:
        a,b = int(input()),set()
        for i in range(a):
            b.add(int(input()))
        for i in sorted(b):
            print(i)
    except:
        break

4.字符串分割

•连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组;
•长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。

def printStr(string):
    while len(string) > 8:
        print(string[:8])
        string = string[8:]
    print(string + "0"*(8-len(string)))
        
a = input()
b = input()
printStr(a)
printStr(b)

5.进制转换

写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。(多组同时输入 )

while True:
    try:
        print(int(input(),16))
    except:
        break

6.质数因子

功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(如180的质因子为2 2 3 3 5 )
最后一个数后面也要有空格

解法:求一个数的因数n的时候只要在range(2,n//2 + 1)范围内求解就行了,因为除去1和n本身是n的因数以外其他,整除被2整除出来的因数之后的数字都是小数,因数必须是整数,这样减少了至少一半的计算量。
7//2=3
" ".join(map(str,res)) + " ":将整数数组拼接成间隔为空格的字符串。

a,res = int(input()),[]
for i in range(2,a//2+1):
    while a%i == 0:
        a = a/i
        res.append(i)
print(" ".join(map(str,res)) + " " if res else str(a) + " ")

7.取近似值

写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于5,向上取整;小于5,则向下取整。
python对于浮点数存储有点抽风(4.5会存储成4.4999999),所以要加上0.001。

print(round(float(input())+0.001))

8.合并表记录

数据表记录包含表索引和数值(int范围的整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。
defaultdict使字典初始值为零,
map(int,input().split())将输入的字符串按照 空格 进行分割,得到一对键值对,然后通过map()转变为int型,最后赋值给m, n
sorted(dd.keys())自动按key排序字典的元素

from collections import defaultdict
while True:
    try:
        a,dd = int(input()),defaultdict(int)
        for i in range(a):
            m,n = map(int,input().split())
            dd[m] += n
        for i in sorted(dd.keys()):
            print(str(i) + " " + str(dd[i]))
    except:
        break 

没有defaultdict的解法:

while True:
    try:
        a,dd = int(input()),{}
        for i in range(a):
            m,n = map(int,input().split())
            if m in dd:
                dd[m] += n
            else:
                dd[m] = n
        for i in sorted(dd.keys()):
            print(str(i) + " " + str(dd[i]))
    except:
        break 

9.提取不重复的整数

输入一个int型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
not in去重

res = ""
for i in input()[::-1]:
    if i not in res:
        res += i
print(res)

set(a)使a去除重复项,但是处于无序状态,sorted(set(a),key=a.index)使去除重复项的a根据引索从小到大排序。
“”.join(str)使字符串{"1","2"}转换为"12",与+作用相同。

a = input()[::-1]
print("".join(sorted(set(a),key=a.index)))

10.字符个数统计

编写一个函数,计算字符串中含有的不同字符的个数。字符在ACSII码范围内(0~127),换行表示结束符,不算在字符里。不在范围内的不作统计。

print(len(set(input())))

判断acsii码范围

print(len(set([i for i in input() if ord(i) in range(128)])))

引入stdin.readline

import sys
print(len(set(list(sys.stdin.readline()))))

11.数字颠倒/12.字符串反转

输入一个整数,将这个整数以字符串的形式逆序输出
程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001


写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)

print(input()[::-1])

13.句子逆序

将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I”
所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符

“”.join(str)使字符串{"1","2"}转换为"12",与+作用相同。

a =input().split()[::-1]
print(" ".join(a))

14.字串的连接最长路径查找

给定n个字符串,请对n个字符串按照字典序排列。
sorted(a)可直接用字典规律排序
list.sort()对已存在的列表进行操作,调用其没有返回值;
sorted(a)函数是返回一个新的list,不在原来的list上进行操作,调用其返回一个排好序的新的list。

a,s = int(input()),[]
for i in range(a):
    s.append(input())
print("\n".join(sorted(s))) #或者 for i in s.sort(): print i
    # 匿名函数,c:入参,c.strip():对入参做去空格处理
sys.stdin.readlines()[1:]
    # 按行读取,第0行是输入的行数,所以从第1行开始
map(lambda c:c.strip(), sys.stdin.readlines()[1:])
    # 把每行读取的字符串,分别去空格处理
list(map(lambda c:c.strip(), sys.stdin.readlines()[1:]))
    # 把map结果转为list
sorted(list(map(lambda c:c.strip(), sys.stdin.readlines()[1:])), key=lambda c:c)
    # key:用来进行排序时比较的元素(按asc大小排序),这里是list中的元素,即按行读取并去空格的字符串
for i in sorted(list(map(lambda c:c.strip(), sys.stdin.readlines()[1:])), key=lambda c:c):print(i)
    # 依次输出排过序的list中的元素

15.求int型正整数在内存中存储时1的个数

输入一个int型的正整数,计算出该int型数据在内存中存储时1的个数。
bin(int)返回二进制的字符串

a = bin(int(input()))
print(a.count("1"))

16.购物单(动态规划-分类背包问题)

王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅 无
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。王强想买的东西很多,为了不超出预算,他把每件物品规定了一个重要度,分为 5 等:用整数 1 ~ 5 表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是 10 元的整数倍)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。
请你帮助王强设计一个满足要求的购物单。
背包问题九讲

#分组背包,每组有四种情况,a.主件 b.主件+附件1 c.主件+附件2 d.主件+附件1+附件2
n,m=map(int,input().split())
n=n//10#价格为10的整数倍,节省时间
v=[[0 for i in range(4)] for j in range(m+1)] #体积 4xm
w=[[0 for i in range(4)] for j in range(m+1)] #价值 4xm
f=[0]*(n+1)
for i in range(1,m+1):
    x,y,z=map(int,input().split())
    x=x//10
    if z==0: #若买主件,其余附件增加同样数量
        for t in range(4):
            v[i][t], w[i][t] = v[i][t]+x, w[i][t]+x* y
    elif v[z][1]==v[z][0]:#若为附件,先添加至b情况,并d情况数量+1
        v[z][1],w[z][1] = v[z][1] + x, w[z][1] + x* y
        v[z][3],w[z][3] = v[z][3] + x, w[z][3] + x* y
    else:#添加附件2
        v[z][2], w[z][2] = v[z][2] + x, w[z][2] + x* y
        v[z][3], w[z][3] = v[z][3] + x, w[z][3] + x* y
# 背包01问题
for i in range(1,m+1): #前i个
    for j in range(n,-1,-1): #体积为j
        for k in range(4): #属于第k个组
            if j>=v[i][k]:
                f[j]=max(f[j],f[j-v[i][k]]+w[i][k])
print(10*f[n])

17.坐标移动

开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从(0,0)点开始移动,从输入字符串里面读取一些坐标,并将最终输入结果输出到输出文件里面。
输入:
合法坐标为A(或者D或者W或者S) + 数字(两位以内)
坐标之间以;分隔。
非法坐标点需要进行丢弃。如AA10; A1A; % ; YAD; 等。
下面是一个简单的例子 如:
A10;S20;W10;D30;X;A1A;B10A11;;A10;
处理过程:
起点(0,0)

  • A10 = (-10,0)
  • S20 = (-10,-20)
  • W10 = (-10,-10)
  • D30 = (20,-10)
  • x = 无效
  • A1A = 无效
  • B10A11 = 无效
  • 一个空 不影响
  • A10 = (10,-10)
    结果 (10, -10)

⚠️str.startswith检查字符串是否是以指定子字符串开头,直接用str[0]当字符串为空时存在越界。
str.isdigit检测字符串是否只由数字组成

while True:
    try:
        a = input().split(";")
        cd = [0,0]
        for i in a:
            if i.startswith("A") and len(i)<=3 and i[1:].isdigit():
                cd[0] += - int(i[1:])
            elif i.startswith("D") and len(i)<=3 and i[1:].isdigit():
                cd[0] += int(i[1:])
            elif i.startswith("W") and len(i)<=3 and i[1:].isdigit():
                cd[1] += int(i[1:])
            elif i.startswith("S") and len(i)<=3 and i[1:].isdigit():
                cd[1] += - int(i[1:])
            else:
                continue
        print("{0},{1}".format(cd[0], cd[1]))
    except:
        break

(cmd and cmd[0])可避免空集cmd[0]报错
for line in sys.stdin: #line='A12;S20;\n'

import sys
dx = [-1,0,0,1]
dy = [0,-1,1,0]
for line in sys.stdin: #line='A12;S20;\n'
    x,y = 0,0
    for cmd in line.split(';'): #cmd='A12'
        if cmd and cmd[0] in 'ASWD': # (cmd and cmd[0])可避免空集cmd[0]报错
            try:
                n = int(cmd[1:]) #若cmd[1:]不能被int化(不是数字),则转入except
                x += n*dx['ASWD'.find(cmd[0])]
                y += n*dy['ASWD'.find(cmd[0])]
            except:
                continue
    print('{0},{1}'.format(x,y))

18.识别有效的IP地址和掩码并进行分类统计

请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。
所有的IP地址划分为 A,B,C,D,E五类
A类地址1.0.0.0~126.255.255.255;
B类地址128.0.0.0~191.255.255.255;
C类地址192.0.0.0~223.255.255.255;
D类地址224.0.0.0~239.255.255.255;
E类地址240.0.0.0~255.255.255.255
私网IP范围是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255
子网掩码为二进制下前面是连续的1,然后全是0。(例如:255.255.255.32就是一个非法的掩码)
注意二进制下全是1或者全是0均为非法
注意
1.类似于【0...*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时可以忽略
2.私有IP地址和A,B,C,D,E类地址是不冲突的
解析
1.255.255.255.255 为非法子网掩码(题目的意思,实际这个掩码,也能用)
2.当子网掩码错误时,不在判断ip是否有效,错误直接加一, 进行下次循环
3.当一个ip属于ABCDE类中的一个时候,也属于私有ip时,私有ip和他属于的分类都应该加一
解题的方法:
1.判断子网掩码是否有效。判断别的子网掩码是否正确。将子网掩码转换成32位0/1组成的二进制字符串,只需要判断该二进制中第一个0和最后一个1的位置即可。
2.判断ip时候有效
3.如果ip地址有效,我们就可以判断它属于哪一类,是否是私有ip

def dec2bin(ip):
    s = ''
    arr = ip.split('.')
    if len(arr) != 4:
        return ''
    for i in arr:
        if len(i) == 0:
            return ''
        temp = bin(int(i))[2:]
        if len(temp) > 8:
            return ''
        if len(temp) < 8:
            temp = '0' * (8 - len(temp)) + temp
        s += temp
    return s
def validMask(mask):
    m = dec2bin(mask)
    if not m:
        return False
    elif (not m.count('0')) or (not m.count('1')) or ('01' in m):
        return False
    else:
        return True
a, b, c, d, e, err, private = 0, 0, 0, 0, 0, 0, 0
while True:
    try:
        ip, mask = input().split('~')
        ip = dec2bin(ip)
        if not validMask(mask) or not ip:
            err += 1
        else:
            if ip >= dec2bin('1.0.0.0') and ip <= dec2bin('126.255.255.255'):
                a += 1
                if ip >= dec2bin('10.0.0.0') and ip <= dec2bin('10.255.255.255'):
                    private += 1
            if ip >= dec2bin('128.0.0.0') and ip <= dec2bin('191.255.255.255'):
                b += 1
                if ip >= dec2bin('172.16.0.0') and ip <= dec2bin('172.31.255.255'):
                    private += 1
            if ip >= dec2bin('192.0.0.0') and ip <= dec2bin('223.255.255.255'):
                c += 1
                if ip >= dec2bin('192.168.0.0') and ip <= dec2bin('192.168.255.255'):
                    private += 1
            if ip >= dec2bin('224.0.0.0') and ip <= dec2bin('239.255.255.255'):
                d += 1
            if ip >= dec2bin('240.0.0.0') and ip <= dec2bin('255.255.255.255'):
                e += 1
    except:
        break
print(a, b, c, d, e, err, private)

19.简单错误记录

开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
处理:
1、 记录最多8条错误记录,循环记录(或者说最后只输出最后出现的八条错误记录),对相同的错误记录(净文件名称和行号完全匹配)只记录一条,错误计数增加;
2、 超过16个字符的文件名称,只记录文件的最后有效16个字符;
3、 输入的文件可能带路径,记录文件名称不能带路径。
解析
使用Python字典判断是否为重复出现的错误信息,输出的重点问题在于输出最后八条记录时,输出的应该为8条不重复的记录,filelist应该在每条错误信息第一次出现时记录,重复出现不记录。
str.split('\\')\分成不同字符串

err = {}
filelist = []
while True:
    try:
        record = input().split('\\')[-1] #'fpgadrive.c   1325'
        record = ' '.join(record.split()) #'fpgadrive.c 1325'
        filename = record.split()
        if len(filename[0]) > 16:
            filename[0] = filename[0][-16:]
        record = ' '.join(filename)
        if record in err.keys():
            err[record] += 1
        else:
            err[record] = 1
            filelist.append(record)
    except:
        break
key = filelist[-8:]
for i in key:
    print(i,err[i])

20.密码验证合格程序

密码要求:
1.长度超过8位
2.包括大小写字母.数字.其它符号,以上四种至少三种
3.不能有相同长度超2的子串重复
说明:长度超过2的子串
解析
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
re.search('[0-9]',str) 扫描整个字符串并返回第一个成功的匹配。

import re
while True:
    try:
        s,li = input(),[]
        # 1.长度超过8位
        if len(s) < 9:
            print('NG')
        else:
            # 2.包括大小写字母.数字.其它符号,以上四种至少三种
            count = 0
            if re.search('[0-9]',s): count += 1
            if re.search('[A-Z]',s): count += 1
            if re.search('[a-z]',s): count += 1
            if re.search('[^0-9A-Za-z]',s): count += 1
            # 3.不能有相同长度超2的子串重复
            for i in range(len(s)-2):
                li.append(s[i:i+3])
            len1 = len(li)
            len2 = len(set(li))
            if count > 2 and len1==len2:
                print('OK')
            else:
                print('NG')
    except:
        break

21.简单密码

假设渊子原来一个BBS上的密码为zvbo9441987,为了方便记忆,他通过一种算法把这个密码变换成YUANzhi1987,这个密码是他的名字和出生年份,怎么忘都忘不了,而且可以明目张胆地放在显眼的地方而不被别人知道真正的密码。
他是这么变换的,大家都知道手机上的字母: 1–1, abc–2, def–3, ghi–4, jkl–5, mno–6, pqrs–7, tuv–8 wxyz–9, 0–0,就这么简单,渊子把密码中出现的小写字母都变成对应的数字,数字和其他的符号都不做变换,
声明:密码中没有空格,而密码中出现的大写字母则变成小写之后往后移一位,如:X,先变成小写,再往后移一位,不就是y了嘛,简单吧。记住,z往后移是a哦。
解析:
str.islower() 方法检测字符串是否由小写字母组成。
str.isupper() 方法检测字符串是否由大写字母组成。
str.lower()转换字符串中所有大写字符为小写。
ord() 函数是 chr() 函数(对于 8 位的 ASCII 字符串)的配对函数。

dict={'abc':2,'def':3,'ghi':4,'jkl':5,'mno':6,'pqrs':7,'tuv':8,'wxyz':9}
while True:
    try:
        s,res = input(),''
        for i in s:
            if i.islower():
                for j in dict.keys():
                    if i in j:
                        res += str(dict[j])
            elif i.isupper():
                if i == 'Z':
                    res += 'a'
                else:
                    res += chr(ord(i.lower())+1)
            else:
                res += i
        print(res)
    except:
        break

最优分割(动态规划-分割)

依次给出n个正整数A1,A2,… ,An,将这n个数分割成m段,每一段内的所有数的和记为这一段的权重, m段权重的最大值记为本次分割的权重。问所有分割方案中分割权重的最小值是多少?
解析
假设存在一个最大值的最小值 x,反过来划分数组。子数组的权值都比x要小,如果组数小于m,说明 x 还可以再小;组数大于m,说明 x 需要变大,以容纳更多的数,减小分组数;如果组数等于m,x也可能再小
* 考虑边界情况,现在把每个元素分成一组,那么x的最小值就是数组中最大的值;把数组当成一个组,那么x就是数组元素之和。
* 即 max(nums) <= x <= sum(nums)
* 因为每一组都是连续的,只要每一组累加的和大于了x,那么当前元素就要放到下一组,记录有多少组即可。
* 我们通过二分逼近来确定这个x的值。
* 在于这个“逼近”,这道题是在连续的数值范围中逼近,换句话说,每个组的和一定在范围之内,因此正确答案是不会被跳过的;
list(map(int,input().split())):{‘45’,‘56’}转换为int的列表[45.56]

n,m = map(int,input().split())
num = list(map(int,input().split()))
left = max(num)
right = sum(num)
ans = right
while left < right:
    mid = (left+right)//2
    count = 1 # 记录数组的个数
    res = 0
    for i in range(n):
        # 直到当前子数组的和加上当前元素比mid还大,
        # 那必须将当前元素归为下一个子数组中,
        # res重新计算新子数组的和
        if res+num[i] > mid:
            count += 1
            res = num[i]
        else:
            res += num[i] # 当前子数组的和比mid小,继续加
    # 如果分完之后组数小于等于m说明,mid还可以更小,
    # 右区间缩小到mid-1;
    if count <= m:
        ans = min(ans,mid)
        right = mid
    else:
        left = mid+1 # //向小取整,(5+6)//2=5,left和right永远不相等
print(ans)

你可能感兴趣的:(剑指offer)