2.3
问题描述
有 \(n\) 个人围成一圈,顺序排号。从第一个人开始报数(从 \(1\) 到 \(3\) 报数),凡报到 \(3\)
思路分析
实际上这是个约瑟夫环问题。但是题目没有要求复杂度,我们简单的实现就好了。
根据关键词退出圈子,不难想到:
del
x.remove()
于是我们很容易写出这样一个错误的代码:
n = int(input('输入数字:')) # 输入数字
arr = list(range(1, n + 1, 1)) # 建立一个列表,存放的是号码数
cnt = 0 # 记录当前报的号是多少
while len(arr) > 1:
for i in range(len(arr)):
cnt += 1
if (cnt % 3 == 0):
del arr[i]
print(arr[0])
但是这个代码会报错,出现:
IndexError: list assignment index out of range
也就是,索引越界。
为什么会出现这个问题呢?答案是:当你del
or remove
一个元素之后,列表的长度会发生变化!!!
举个例子:
arr = [1, 2, 3]
# 这时候我们访问 arr[2]
print(arr[2])
# 会输出 3
del arr[1]
# 在删除 arr[1] 之后我们再进行访问 arr[3] 会怎么样呢?
print(arr[3])
# IndexError: list index out of range 会出现越界的错误
# 这是因为,del 之后,list 的长度发生了变化
因此,为了避免这个问题,我们可以设置两个列表 arr
和 brr
。在每次操作开始前,我们保证 brr = arr
我们寻找 brr
中的每个元素,假如发现他所报号正好 %3 == 0
,我们就在arr
里面删除它。为啥不在 brr
里面删除而在 arr
里面删呢? 因为在 arr
里面删除不会改变 brr
的长度,这样就不会出现,索引越界的情况。
代码
"""
Problem:
有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),
凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
Solution:
实际上这个是个约瑟夫环问题,但是我们简单的implementation就好了
"""
n = int(input('输入数字:')) # 输入数字
arr = list(range(1, n + 1, 1)) # 建立一个列表,存放的是号码数
cnt = 0 # 记录当前报的号是多少
# 循环直到列表只剩一个元素
while len(arr) > 1:
brr = arr[:] # 列表切片,复制列表,为下一步删除做准备
# brr 中的每个元素进行报数,符合条件的在 arr 中删除
for i in range(len(brr)):
cnt += 1 # 进行报号
if cnt % 3 == 0: # 如果报3,则去除a中的这一位
arr.remove(brr[i])
print(arr[0])
2.4
问题描述
输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组。
思路分析
这题非常简单,我们提取关键词:1.最大值, 2.最小值,3.交换
关于 1.2,我们需要做的是:
- 找到最大最小值
mx
,mn
- 找到极值对应的索引
mx_idx
,mn_idx
关于 3交换,我们运用 Python 里面的元组只是:
-
a, b = b, a
就可以实现交换
因此整个流程:
- 通过
max
min
函数找到最大最小值 - 通过
for
循环找到最大最小值对应的索引 - 交换即可
那么聪明的 yzy
能不能不看代码实现呢!
代码
"""
Problem:
输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组。
Solution:
implementation 简单实现即可
"""
# 简单的接收列表
n = int(input("Please input a number as the length of list"))
arr = [None] * n
for i in range(n):
x = int(input("输入元素")); arr[i] = x
print(arr)
# 首先找到最大的元素,最大用 mx 而不是 max 表示
# 注意,这里找到最大的元素不管用,需要找到最大元素的索引(因为要实现交换),最小值同理
mx, mn = max(arr), min(arr)
mx_idx, mn_idx = -1, -1 # 初始化 最大值的下标和最小值的下标
# 通过以下 for 循环,我们可以找到对应极值的索引
for i in range(n):
if arr[i] == mx and mx_idx == -1: mx_idx = i
if arr[i] == mn and mn_idx == -1: mn_idx = i
# 实现交换即可, 在 python 中 a, b = b, a 即可实现交换
arr[mx_idx], arr[0] = arr[0], arr[mx_idx]
arr[mn_idx], arr[n - 1] = arr[n - 1], arr[mn_idx]
print(arr)
# 结果
Please input a number as the length of list7
输入元素5
输入元素3
输入元素10
输入元素3
输入元素1
输入元素9
输入元素5
[5, 3, 10, 3, 1, 9, 5]
[10, 3, 5, 3, 5, 9, 1]
3.1
问题描述
求一个 \(3\times3\)
思路分析
过于简单,可能难点在于 二维数组 如何建立吧,然后简单计算即可!!
代码
"""
Problem:
求一个3*3矩阵对角线元素之和。
Solution:
implementation 然后 tot = arr[1][1] + arr[2][2] + arr[3][3]
"""
arr = [ [None] * 3 ] * 3
for i in range(3):
for j in range(3):
x = int(input("请输入(%d, %d)的元素" % (i, j))); arr[i][j] = x
print(arr)
# 假设计算的是 (0, 0) (1, 1) (2, 2) 的对角线之和
tot = 0
for i in range(3):
tot += arr[i][i]
print(tot)
3.2
问题描述
一个 \(5\) 位数,判断它是不是回文数。即 \(12321\)
思路分析
这里提供一个思路,就是把数字转换为字符串,再判断是否为回文串
例如: \(num = 12321\) ,我们首先转化,ss = str(num)
然后我们可以这样表示: \(ss=1 2 3 2 1\),我们设两个索引:
-
left = 0
,指向最开始,用于从左边扫描 -
right = len(ss) - 1
,指向最后,用于从右边扫描
为了更加清晰的作图,我们做一下变化l = left, r = right
(这里你可能会看不懂,没关系,看下面!!)
\[\begin{array}{l} ss=\overset{l=0}{\overbrace{1}}\;2\;3\;2\overset{r=4}{\overbrace{1}} \\ ss=1\;\overset{l=1}{\overbrace{2}}\;3\;\overset{r=3}{\overbrace{2}}\;1 \\ ss=1\;2\;\overset{l=r=2}{\overbrace{3}}\;2\;1 \end{array} \]
我们 l
从左往右扫描,r
从右往左扫描:
- 如果
ss[l] == ss[r]
则他们相互靠近一格。 - 如果不同则直接
break
。 - 如果
l >= r
时,说明该字符串(数字)为一个回文串。
代码
"""
Problem:
一个5位数,判断它是不是回文数。即12321是回文数,
个位与万位相同,十位与千位相同。
Solution:
可以转为 str 之后用两个下标循环处理!
"""
import random
# 随机生成一个 5 位数
num = random.randint(10000, 99999)
print("生成的五位数是: %d" % num)
# 我们把它转为一个字符串,这样我们就能用下标访问了!
ss = str(num)
# 设置两个元素,从左到右,从右到左进行扫描
left, right = 0, len(ss) - 1
# 设置 flag ,假如 flag 为 True 则为回文,否则则不为回文
flag = True
while (left < right):
# 发现有个元素不同,则肯定不回文,设置 flag = False 然后退出循环
if (ss[left] != ss[right]):
flag = False
break
left += 1 # 左边的往右
right -= 1 # 右边的往左
if (flag):
print("是回文串")
else:
print("不是回文串")
3.3
问题描述
求 \(1+2!+3!+...+20!\)
思路分析
首先阶乘的定义是啥?
阶乘: \(x! = 1 \times 2 \times \cdots\times x\)
假设 \(fac(x) := x!\) ,我们容易得到一个推导式: \(fac(x) = fac(x-1) * x\)
要计算 \(1+2!+3!+...+20!\)
代码
"""
Problem:
求1+2!+3!+...+20!的和。
Solution:
x! 代表阶乘, x! = x * (x - 1)!
因此,我们设一个数组 fac[n],其中 fac[i] := i!, fac[i + 1] = (i + 1) * fac[i]
"""
# 因为要计算的范围是 1 -- 20 所以设最大为 21
fac = [None] * 21
# 设置初值
fac[0] = 1
# tot --> total 代表总答案
tot = 0
for i in range(1, 21, 1):
fac[i] = i * fac[i - 1]
tot += fac[i]
print(tot)
# 2561327494111820313
3.4
问题描述
有一分数序列:\(\dfrac{2}{1},\dfrac{3}{2},\dfrac{5}{3},\dfrac{8}{5},\dfrac{13}{8},\dfrac{21}{13} \cdots\)求出这个数列的前 \(20\)
思路分析
这里的难点在于发现序列分子,分母对应的规律。
思考一下发现,上下分子分母都是一个类似斐波那契数列的规律:
- 2, 3, 5(2+3),8(3+5)
- 1, 2, 3(1+2),5(2+3)
因此,我们可以先推导出分子分母各为什么,再计算答案:
不妨设:
upper(i) := 第 i 个元素的分母
lower(i) := 第 i 个元素的分子
显然,他们都拥有相同的规律:
upper(i) = upper(i - 1) + upper(i - 2)
lower(i) = lower(i - 1) + lower(i - 2)
因此,我们可以先计算出上下分母分子再用一个 for
循环计算答案!
代码
"""
Problem:
有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13...求出这个数列的前20项之和。
Solution:
这题有点难度,因为上面下面实际上都是一个斐波那契数列,
不妨设上面的第 i 个为 upper(i)
不妨设下面的第 i 个为 lower(i)
则: upper(i) = upper(i - 1) + upper(i - 2)
同: lower(i) = lower(i - 1) + lower(i - 2)
通过递推式计算即可!
"""
upper = [None] * 20
lower = [None] * 20
upper[0], upper[1] = 2, 3
lower[0], lower[1] = 1, 2
for i in range(2, 20, 1):
upper[i] = upper[i - 1] + upper[i - 2]
lower[i] = lower[i - 1] + lower[i - 2]
ans = 0.0
for i in range(20):
ans += (upper[i] / lower[i])
print("答案为 %.4f" % ans)
# 答案为 32.6603
函数章节的作业
1
"""
Q:
依次从控制台输入多个整数,以整数-1作为输入结束标记,编写程序找出其中的最大数和最小数
"""
x = int(input("请输入一个整数"))
mx, mn = x, x # mx --> max, mn --> min
while x != -1:
mx = max(mx, x)
mn = min(mn, x)
# 思考下为啥放最后(因为不放最后会把 -1 也给考虑进来)
x = int(input("请输入一个整数"))
print("最大值为 %d, 最小值为 %d" % (mx, mn))
2
"""
Q:
利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来。
Solution:
稍微有点难度,没搞懂没关系
"""
n = 5
def rec_print(cnt):
"""
cnt: 代表当前是第几层递归
"""
if (cnt == 5): return
char = input("请输入一个字符") # 接收输入
rec_print(cnt + 1) # 直接递归到下一个元素
print(char) # 之前的元素全部处理好之后输出
rec_print(0)
3
"""
Q:
编写程序将一个不确定位数的正整数进行三位分节后输出,如输入1234567,输出1,234,567。
"""
# 法一,字符串模拟
x = int(input("请输入一个数字"))
if (len(str(x)) < 3): # 假如小于 3 直接切片就会越界! 意识到了嘛!
print(x)
else:
print(str(x)[-3:])
# 法二,数学方法
ans = ""
x = int(input("请输入一个数字"))
for i in range(3):
ans += str(x % 10) # 直接 %10 取低位
x = x // 10 # 往右移一位, 记得整除!
print(ans[::-1]) # 翻转
4
"""
Q:
请分别用递归技术和迭代技术,将一个十进制正整数,以七进制形式打印在屏幕上。
"""
# 迭代版本
num = int(input("请输入一个数字"))
res = 0 # 存储结果
base = 1 # 存储基数,也就是当前第几位了 eg: 205 这个2就是 2 * 100
while num > 0:
t = num % 7 # 当前位的数组
num = num // 7 # 修改num数字大小
res += (t * base) # 更新答案
base *= 10 # base 增加一位
print(res)
# 递归版本
# 看不懂没关系,我到时候和猪猪讲!!!!
def ten2seven(cur, base):
if (cur <= 0): return 0
res = (cur % 7) * base
return res + ten2seven(cur // 7, base * 10)
num = int(input("请输入数字"))
print(ten2seven(num, 1))