中国大学MOOC实用Python程序设计学习笔记和课后测试1-3周(北京大学)
这门课由于较早开设,大概是年初,刚好趁着学习热情开始学习,郭老师教学幽默风趣,教学内容的的确确是很实在的干货,但是学完并且消化吸收谈何容易?还需要不断地练习、出错、纠错后再强化。这门课的课后测试题需要在OpenJudge平台上练习并通过,之前只是跟着课件学习并且在pycharm里练习,以及在印象笔记里整理截图,随时回顾,但是我依然没有真正掌握,课后练习也有不理解的地方,对于小白的我来说还有很多疑问点,所以在此决定认真做一个学习笔记集,欢迎编程大佬批评指正,不断努力提升!
查错的技巧:
自己做测试数据,让所有代码分支都能被执行到并看其结果。
例如,程序有三个分支,那么针对每个分支出一两组数据测一下,对查错大有帮助。一部分的代码,从来没看过其运行的结果,那当然不可靠。
调试时,可以在程序各处加print语句,观察那部分代码是否被执行过,以及某些变量的值是不是正确。
第1周 Python初探
以命令行方式运行python程序Windows下,Win+R 键,可以弹出左边“运行”窗口,敲"cmd"确定,就能弹出右边
cmd窗口(命令行窗口)
敲 cd
再敲 cd \tmp (或其它文件夹名)
进入存放python程序的文件夹
python XXX.py就可以运行XXX.py
为project设置解释器
如果pycharm找不到python interpereter, 则: File|Settings|Project: XXX |Project
interpreter,然后选解释器。如果没得选,就add local加一个,加的办法是选python
安装的文件夹。
保留字
有些名字Python预留了,不可用作变量的名字
and as assert break class continue def
del elif else except exec for finally from
global if import in is lambda not or pass
print raise return try while with yield
第1周课后测试题
提交答案合格
#001.字符菱形
a = input()
print(" "+ a)
print(" "+a*3)
print(a*5)
print(" "+a*3)
print(" "+a)
#002.字符三角形
a = input()
print(" " + a)
print(" " + a*3)
print(a*5)
#003.输出第二个整数
print(input().split()[1])
#004.求三个数的和
s = input().split()
a,b,c = float(s[0]),float(s[1]),float(s[2])
print(a + b + c)
#005.判断子串:输入两行字符串,要求判断第一行 字符串是不是第二行的子串
s1 = input()
s2 = input()
if s1 in s2:
print("YES")
else:
print("NO")
#006.计算(a+b)*c的值:给定3个整数a、b、c,计算表达式(a+b)*c的值。
s = input().split()
a,b,c = int(s[0]),int(s[1]),int(s[2])
print((a + b)* c)
#007.反向输出一个三位数
n = input()
print(n[2]+n[1]+n[0])
#或者
print(n[::-1])
#008.字符串交换:输入两个长度为4的字符串,交换这两个字符串的前两个字符后输出
s1 = input().split()
s2 = input().split()
print(s2[0][0] + s2[0][1] + s1[0][2] + s1[0][3])
print(s1[0][0] + s1[0][1] + s2[0][2] + s2[0][3])
#或者
print(s2[0:2]+s1[2:4]+'\n'+s1[0:2]+s2[2:4])
#009.字符串中的整数求和:输入两个长度为3的字符串,每个串前两个字符是数字,后一个字符是字母。 求这两个串中的整数的和
s = input().split()
print(int(s[0][0] + s[0][1]) + int(s[1][0] + s[1][1]))
第2周 基本运算、条件分支和输出格式控制
各类运算符
条件分支语句
if 语句嵌套
输出格式控制
第2周课后测试题
提交答案合格
010:计算2的幂
注意点:
int函数,幂次运算,可以使用pow函数
n=int(input())
#或者使用s=2**n
s=pow(2,n)
print(s)
011:计算多项式的值
注意点:
格式控制符 %.nf的用法
s=input().split()
x,a,b,c,d=float(s[0]),float(s[1]),float(s[2]),float(s[3]),float(s[4])
y=a*x**3+b*x**2+c*x+d
print("%.7f"%y)
012:奇偶数判断:给定一个整数,判断该数是奇数还是偶数。
注意点:
if,else判断,模运算,也可以用eval函数
n=int(input())
if n%2==0:
print("even")
else:
print("odd")
013:点和正方形的关系
注意点:
split函数,考虑边界条件-1<=x<=1,-1<=y<=1,比较运算符、关系运算符的使用
看清题目已知条件,x,y都是整数所以不需要使用float
s = input().split()
x,y = int(s[0]),int(s[1])
if -1 <= x <= 1 and -1 <= y <= 1:
print("yes")
else:
print("no")
014:三角形判断:给定三个正整数,分别表示三条线段的长度,判断这三条线段能否构成一个三角形。
注意点:
和正方形判断注意点相同,但是输入方式可以使用map转换函数
a,b,c =map(int,input().split())
if a + b > c and a + c > b and b + c > a:
print("yes")
else:
print("no")
015:计算邮资
测试点:1500 y
输出:17
注意点:
if语句, True可以当 1用; == , <= , % , // 等用法。
// 除法的结果一定是整数部分(商)。
/ 的结果一定是小数。
注意题目要求题目要求整数(如果产生小数需要考虑整除用法)。
注意临界点。
#方法1:根据是否加急判断
s = input().split()
k,c =int(s[0]),s[1]#分别表示邮件重量和是否加急
if c=="y":
if k>1000:
if (k -1000) % 500==0:#当邮资为临界点时
sum=8 + 4*((k - 1000) // 500)+5
print(sum)
else:
sum = 8 + 4 * ((k - 1000) // 500 +1) + 5
print(sum)
else:
print(8+5)
else:
if k>1000:
if (k - 1000) % 500 == 0: # 当邮资为临界点时
sum = 8 + 4 * ((k - 1000) // 500)
print(sum)
else:
sum = 8 + 4 * ((k - 1000) // 500 + 1)
print(sum)
else:
print(8)
#方法2:根据邮资重量判断
s = input().split()
k,c =int(s[0]),s[1]
if k > 1000:
if (k -1000) % 500 != 0:
sum = 8 + 4*((k - 1000) // 500 + 1)
if c == "y":
sum = sum + 5
print(sum)
elif c == "n":
print(sum)
else:
sum = 8 + 4*((k -1000) // 500)
if c == "y":
sum = sum + 5
print(sum)
elif c == "n":
print(sum)
else:
if c == "y":
print(8 + 5)
elif c == "n":
print(8)
016:分段函数
注意点:
if 语句的用法
float(x)能把字符串x转换成小数, %.nf格式控制符的用法, and的用法,
4 < 5 < 6 这样的表达式值为True
#016 分段函数
x = float(input())
if 0 <= x < 5:
y = 2.5 - x
print("%.3f" % y)
elif 5 <= x < 10:
y = 2 - 1.5*(x - 3) *(x - 3)
print("%.3f" % y)
elif 10 <= x < 20:
y = x/2 - 1.5
print("%.3f" % y)
else:
pass
017:简单计算器
注意点:
如果x是小数,int(x) 可以得到x的整数部分(去尾去整)。本题需要用这个方法求除法的整数结果。
注意操作数为负数时 // 的情况, -9//4 = -3, 而 int(-9/4) = -2。
如果会用 in和列表,以及eval(),程序可以很简洁 (拼一个 算术表达式 字符串 然后用 eval)。
“+" "-"等字符串无法转成运算符。要自己判断,读到 + 就做加法,读到 - 就做减法。
%.0f 输出会四舍五入,不要使用。
#017 简单计算器
#一个最简单的计算器,支持+, -, *, / 四种运算。仅需考虑输入输出为整数的情况(除法结果就是商,忽略余数)
#输入:输入只有一行,共有三个参数,其中第1、2个参数为整数,第3个参数为操作符(+,-,*,/)。
#输出:输出只有一行,一个整数,为运算结果。然而:
#1. 如果出现除数为0的情况,则输出:Divided by zero!
#2. 如果出现无效的操作符(即不为 +, -, *, / 之一),则输出:Invalid operator!
#方法1:
s = input().split()
a,b,c = int(s[0]),int(s[1]),s[2]
if c in ["+","-","*","/"]:
if c=="+":
print(a + b)
elif c == "-":
print(a - b)
elif c == "*":
print(a * b)
else:
if b==0:
print("Divided by zero!")
else:
print(a/b)
else:
print("Invalid operator!")
#方法2:
a =input().split()
x,y,z = int(a[0]),int(a[1]),a[2]
if z not in "+-*/":
print('Invalid operator!')
else:
if z=='/' and y == 0:
print("Divided by zero!")
else:
print('%d' % eval(str(x)+z+str(y)))
018:大象喝水
注意点:
当做数学问题来解决,数学思维程序化转换。
#018 大象喝水
h,r = map(int,input().split())
Pi = 3.14159
sum = Pi*r*r*h/1000
print(int(20 / sum + 1))
019:苹果和虫子2
注意点:
整数除法 // 的用法
各种边界数据(特殊数据,比如0,1,负数之类),以及计算结果的合法性。
与计算邮资有点类似,需要判断临界值
#019 苹果和虫子
#n,x,y分别表示苹果个数,虫子吃一个苹果的小时数,使用时间
n,x,y=map(int,input().split())
if n>y/x:
if y % x != 0:
print(n - int(y / x) - 1)
else:
print(n - int(y / x))
else:
print(0)
020:求一元二次方程的根
测试点:1 0 7.3
输出:x1=0.00000+2.70185i;x2=0.00000-2.70185i
本题注意点:
1.浮点数输入和format格式化输出的注意点。
2.数值运算注意点,比如-b/2*a 是 (-b/2)a,不是 -b/(2a),以及虚数运算、绝对值函数的运算。
3.由于计算机存在误差点,判断两个小数相等最好不要用 a == b形式,应该用 abs(a-b) < eps的形式。避免输出 -0.00000,需要自己去判断,如果要输出x是个接近0的很小的数,由于我们format操作后保留六位小数相当于0但是会有负号,所以需要考虑令x = 0后输出。(eps可以是一个很小的数,比如eps = 0.000001 )
import math
s = input().split()#input里不需要加内容,OpenJudge容易出错!注意split的用法。
a,b,c = float(s[0]),float(s[1]),float(s[2])#浮点数输出
t=b*b-4*a*c
m=math.sqrt(abs(t))/(2*a)#一般很长的代码可以赋值简化
eps = 0.0000001#这里取一个很小的数
if abs(t) - eps <0:#引入绝对值函数,由于t=0在计算机中有误差,故使用eps
if abs(-b/(2*a))-eps < 0:
b=0
print("x1=x2=%.5f" % (-b/(2*a)))
else:
print("x1=x2=%.5f" % (-b/(2*a)))
elif t > 0:
print("x1=%.5f;x2=%.5f" % ((-b+math.sqrt(t))/(2*a),(-b-math.sqrt(t))/(2*a)))
else:
if abs(-b/(2*a)) - eps <0:#实部为一个很小的接近0的数,如果输出保留精度会产生负号
b=0
print("x1={:.5f}+{:.5f}i;x2={:.5f}{:.5f}i".format(-b/(2*a),m,-b/(2*a),m*(-1)))
else:
print("x1={:.5f}+{:.5f}i;x2={:.5f}{:.5f}i".format(-b/(2*a),m,b/(2*a)*(-1),m*(-1)))
第3周 循环语句
for 循环
for i in range():
遍历
len()
break 语句
跳出本循环
continue语句
跳出本次,进行下一次循环
字符的编码
ord(x) 求字符 x 的编码 (字符就是长度为1的字符串)
chr(x) 求编码为x的字符
字母的ASCII编码是连续的
代码:
#连续输出26个字母
for i in range(26):
print(chr(ord("a") + i),end="")
例题1. 输入n个整数求和
#例题1. 输入n个整数求和
n=int(input())
total=0
for i in range(n):
total+=int(input())
print(total)
例题2. 从小到大输出n的因子
#例题2. 从小到大输出n的因子
n=int(input())
for x in range(1,n+1):#需要从1开始,排除分母为零
if n%x==0:
print(x," ",end="")
例题3. 从大到小输出n的因子
#例题3. 从大到小输出n的因子
n=int(input())
for x in range(n,0,-1):#此时0是取不到的
if n%x==0:
print(x," ",end="")
多重循环
多重循环例题1:多次求n个数的和
多重循环例题1:多次求n个数的和
m=int(input())#m组数据
for i in range(m):
n=int(input())
total=0
for i in range(n):
total+=int(input())#n行输入求和
print(total)
多重循环例题2: 取两个数![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/9aa825df0cc8a80b6090d22924f13c50.png)
多重循环例题2: 取两个数
n,m=map(int,input().split())
total=0
for i in range(1,n):#n-1个数
for j in range(i+1,n+1):#避免重复
if m%(i+j)==0:
print(i,j)
total+=1
print(total)
多重循环中的break
#多重循环中的break
n,m=map(int,input().split())
total=0
for i in range(1,n):
for j in range(i+1,n+1):
if m%(i+j)==0:
print(i,j)
total+=1
break
print(total)
while循环
例题:输入三个整数,求它们的最小公倍数
#例题:输入三个整数,求它们的最小公倍数
x,y,z=map(int,input().split())
n=m=max(x,y,z)
while True:
if n%x==0 and x%y==0 and n%z==0:
print(n)
break
n+=m
异常处理
用以判断输入是否结束,避免出错。
循环综合例题:求斐波那些数列第k项(为以后函数递归铺垫)
#循环综合例题:求斐波那些数列第k项
k=int(input())
if k==1 or k==2:
print(1)
else:
a1=a2=1
for i in range(k-2):
a1,a2=a2,a1+a2
print(a2)
例题:求阶乘的和
# 例题:求阶乘的和
n=int(input())
total,s=0,1
for i in range(1,n+1):
s*=i
total+=s
print(total)
输入正整数n,求不大于n的全部质数
#输入正整数n,求不大于n的全部质数
n=int(input())
print(2)
for i in range(3,n+1,2):#只判断奇数
ok=True
for k in range(3,i,2):
if i%k==0:
ok=False
break
if k*k > i:
break
if ok:
print(i)
第3周课后测试题
提交答案合格
021:求整数的和与均值
注意点:
用循环控制输入
#021:求整数的和与均值
n=int(input())
sum=0
for i in range(n):
m=int(input())
sum+=m
avg=sum/n
print("%d %.5f"%(sum,avg))
022:整数序列的元素最大跨度值
注意点:
使用 min函数和max函数
#022:整数序列的元素最大跨度值
#给定一个长度为n的非负整数序列,请计算序列的最大跨度值(最大跨度值 = 最大值减去最小值)。
n=int(input())
s=input().split()
maxv=minv=int(s[0])
for i in s:
maxv=max(maxv,int(i))
minv=min(minv,int(i))
print(maxv-minv)
023:奥运奖牌计数
注意点:
想象为一个二维数组,求每一列之和还有总和,多尝试使用map转换函数可以使代码更简洁
#023 奥运奖牌计数
#这种方法是不使用序列等工具,带点数学思维,当然使用列表会很方便,不过在这一章使用其他方法也挺好,符合主题毕竟。
n = int(input())
a,b,c = 0,0,0
for i in range(n):#依次输入n-1次
a0,b0,c0=map(int,input().split())#取每一次第一个输入的数
a+=a0
b+=b0
c+=c0
print(a,b,c,a+b+c)
其他代码:
a=int(input())
p=[0,0,0]
for i in range(0,a):
b=input().split()
for j in range(0,3):
p[j]+=int(b[j])
print('%d %d %d %d' %(p[0],p[1],p[2],sum(p)))
024:鸡尾酒疗法
注意点:
if,else的灵活使用,如果搭配列表,学会构造空列表和使用append函数。
本人见解:
说说我本人选择这种方法的原因,索性使用列表来做,思路是构建两个空列表,一个存放计算出的有效率y的值,另一个存放输出的判断效果。
做练习提交有时候会出现这种多输入的情况,也就是比如第一行输入5表示之后会再输入5行,那这道题是希望你每次输入一行计算机立刻判断结果比如输出same,还是等几行输入结束后再回车反馈几个结果?
不过提交好像对这个没有明确要求,考虑一下也是对自己思维的提升。
以上是两种输出方式对比。
#024:鸡尾酒疗法
#我的方法
n=int(input())
a,b=map(int,input().split())
x=b/a
lst1,lst2=[],[]
for i in range(n-1):
s=input().split()
t=int(s[1])/int(s[0])
lst1.append(t)
#print(lst1)
for i in range(len(lst1)):
y=lst1[i]
if y-x>0.05:
lst2.append("better")
elif x-y>0.05:
lst2.append("worse")
else:
lst2.append("same")
for i in range(len(lst2)):
print(lst2[i])
#简便方式,输入及判断
n=int(input())
a,b=map(int,input().split())
x=b/a
for i in range(n-1):
s=input().split()
y=int(s[1])/int(s[0])
if y-x > 0.05:
print('better')
elif x-y > 0.05:
print('worse')
else:
print('same')
025 角谷猜想
注意点:
可以使用整数除法 //
用 + 可以连接几个字符串,但是不能用来把字符串和整数连在一起
可以使用 while 循环,注意设置while循环的终止条件
#025 角谷猜想
#是指对于任意一个正整数,如果是奇数,则乘3加1,如果是偶数,则除以2,得到的结果再按照上述规则重复处理,最终总能够得到1。如,假定初始整数为5,计算过程分别为16、8、4、2、1。
#程序要求输入一个整数,将经过处理得到1的过程输出来。
n = int(input())
while n!=1:
if n%2:
print("%d*3+1=%d"%(n,n*3+1))
n=3*n+1
else:
print("%d/2=%d"%(n,n/2))
#或者n=n/2
n//=2
print("End")
026 正常血压
注意点:
注意if与and的搭配使用并考虑端点
用一个变量记录当前正常周期的天数
用另一个变量记录当前已经发现的最长正常周期的天数
注意最后一个周期最长且最后一天也正常的情况
可以设个计数值,正常一天就加1,不正常就清0。
s=""
n=int(input())
for i in range(n):
a,b=map(int,input().split())
if 90<=a<=140 and 60<=b<=90:
s += "1"
else:
s += " "
s=s.split(" ")
print(max([len(i) for i in s]))
#或者使用计数器count赋初值
n=int(input())
count,max=0,0
for i in range(n):
a,b=map(int,input().split())
if 90<=a<=140 and 60<=b<=90:
count+=1
if count>max:
max=count
else:
count=0
print(max)
027 数字反转
注意点:
- 可以用 += 的办法 往 “” 上累加一个个字符形成想要的字符串
1)使用 len(x)求x长度(元素个数) - 不要忘了处理 0 的情况
- 列表最后一个元素下标是 -1
- range里面可以指定步长是负数,就能从大到小遍历
- 注意对负数的处理
- 注意结果不能有没用的前导0
#027数字反转
#不过我没有用提示的内容来做,主要希望锻炼自己字符串反转知识的掌握
N=int(input())
if N>=0:
print(int(str(N)[::-1]))
else:
n=str(N)[1:]
n=str(N)[0]+n[::-1]
print(int(n))
#其他方法
a=input()
if a[0]=='-':
a=a[1:]
a=a[::-1]
print('-',end='')
print(int(a))
else:
a=a[::-1]
print(int(a))
028:求特殊自然数
注意点:
- 用枚举法尝试每一个可能的数,可以考虑使用 break在找到符合要求的数时跳出循环
2)如果一个3位 n 进制数,从右到左数第 0,1,2位分别是 a0,a1,a2,则这个数的大小是:
a0 * n^0 + a1 * n^1 + a2 * n^2
(其中*代表乘法 p^q表示p的q次方)
例如, 7进制数 106 ,大小是: 6 * 1 + 0 * 7 + 1 * 49 = 54 - 对一个整数x,要求它的7进制表示形式的每一位(最右边是第0位),用短除法来做:
x % 7 得到 第0位
x = x // 7
x % 7 得到第1位
x = x // 7
x % 7 得到第2位
…直到x变成0
# #028:求特殊自然数
#换个思路,假设选择100-666之间的一个七进制的数
#需要将七进制转换为十进制即可,因为不需要转为九进制
for i in range(100,667):
a72=i//100
a71=i//10%10
a70=i%10
if (a72*7**2+a71*7+a70) == (a70*9**2+a71*9+a72) and a70<=6 and a71<=6 and a72<=6:
print( a72*7**2+a71*7+a70)
print(i)
print(str(i)[::-1])#字符串反转
#其他方法,不过这种简洁不易懂,需要有数学运算的基础。
for i in range(1*7*7+0*7+1,6*7*7+6*7+6+1):
if i%7 == i//9//9%9 and i//7%7 == i//9%9 and i//7//7%7 == i%9:
print('%d'%i)
print('%d%d%d' %(i//7//7%7,i//7%7,i%7))
print('%d%d%d' %(i//9//9%9,i//9%9,i%9))
029 数字统计
注意点:
如果 s 是个字符串,可以用 for x in s:的方式遍历这个字符串的每个字符。
#029 数字统计
#请统计某个给定范围[L, R]的所有整数中,数字2出现的次数。
#比如给定范围[2, 22],数字2在数2中出现了1次,在数12中出现1次,在数20中出现1次,在数21中出现1次,在数22中出现2次,所以数字2在该范围内一共出现了6次。
#方法1:
s = input().split()
L,R = int(s[0]),int(s[1])
total = 0
for i in range(L,R+1):
s = str(i)
for x in s:
if x == '2':
total += 1
print(total)
#方法2:
s = input().split()
L,R = int(s[0]),int(s[1])
total = 0
for i in range(L,R+1):
while i != 0:
m = i % 10
if m == 2:
total += 1
i //= 10
print(total)