实验一
1. 设计算法求数组中相差最小的两个元素(称为最接近数)的差。
import math
def tcn(n):
# 对列表进行排序
n.sort()
# 初始化最接近数的最小值为无穷大
m = math.inf
# 双指针初始化
i = 0
# 遍历循环列表,当j+1大于列表的长度时结束循环
while i <= len(n)-2:
j = i + 1
c = n[j] - n[i]
# 进行最小值替换
if c < m: m = c
i += 1
# 返回最小值
return m
l = int(input("请输入数组的长度:"))
print("输入数组:")
n = [int(input()) for i in range(l)]
m = tcn(n)
print("该数组的最接近数的差为;", m)
实验二
1. 设计算法,判断一个大整数能否被11整除。可以通过以下方法:将该数的十进制表示从右端开始,每两位一组构成一个整数,然后将这些数相加,判断其和能否被11整除。例如,将562843748分割成5,62,84,37和48,然后判断(5+62+84+37+48)能否被11整除。
def z(n):
# 将接收到的整数n转换为字符串形式m
m = str(n)
# 判断字符串的长度是否是偶数还是奇数,初始化定义遍历列表的指针i,整数s
if len(m) % 2 == 0:
# 如果字符串的长度为偶数,则i=0,s=0
i = 0
s = 0
else:
# 如果字符串的长度为奇数,则i = 1,s = int(m[0])
i = 1
s = int(m[0])
while i < len(m):
# 通过指针i遍历整个数组,不断的对m进行切片并累加到s中
s += int(m[i:i + 2])
i += 2
# 最后判断s是否被11整除,能则大整数能被11整除,反之则不能
if s % 11 == 0:
print("{} 能被11整除!".format(n))
else:
print("{} 不能被11整除!".format(n))
z(input("请输入一个大整数:"))
2. 设计算法,在数组r[n]中删除重复的元素,要求移动元素的次数较少并使剩余元素间的相对次序保持不变。
def dl(r):
# 定义接收的列表
n = []
# 遍历输入的列表r
for i in r:
# 如果列表r中的元素不在列表n中则添加到n中
if i not in n:
n.append(i)
# 否则则不进行添加
# 返回删除重复元素后的列表n
return n
l = int(input("请输入数组的长度:"))
print("请输入数组r:")
r = [int(input()) for i in range(l)]
print("删除重复的元素之前的列表为:", r)
print("删除重复的元素之后的列表为:", dl(r))
3. 已知数组A[n]的元素为整型,设计算法将其调整为左右两部分,左边所有元素为奇数,右边所有元素为偶数,要求时间复杂度为O(n),空间复杂度O(1)。
def jo(A):
# 初始化列表a都为0,长度和列表A一样
a = [0 for _ in range(len(A))]
# 初始化双指针,分别指向列表a的头和尾
i, j = 0, len(A) - 1
# 遍历列表A,k指向列表A中的元素
for k in A:
# 判断元素k是否为奇数
# 是则从前往列表a中加
if k % 2 != 0:
a[i] = k
i += 1
# 否则就从列表a尾巴往前面加
else:
a[j] = k
j -= 1
# 返回调整之后的列表a
return a
l = int(input("请输入数组A的长度:"))
print("请输入列表的元素:")
A = [int(input()) for i in range(l)]
print("调整前:", A)
print("调整后:", jo(A))
4. 设计蛮力算法求解小规模的线性规划问题。假设约束条件:①x + y <= 34;②x+3*y <= 6; ③x >= 0 且 y >= 0,使目标函数3*x + 5*y取得极大值。
m = 0
# 蛮力法求解
for x in range(5):
for y in range(3):
# 与最大值进行比较
if m < 3 * x + 5 * y:
if x + y <= 4 and x + 3 * y <= 6:
m = 3 * x + 5 * y
print("极大值为:", m)
实验三
1. 设计分治算法,实现将数组A[n]中所有元素循环左移k个位置,要求时间复杂度为O(n),空间复杂度为O(1)。例如,对abcdefgh循环左移三位得到defghabc。
def rv(A, k):
# 列表A的长度
l = len(A)
# 判断需要向左移的位数,如果大于等于列表A的长度l,则需要进行取余操作,即k = k % l
if k >= l:
k = k % l
# 此处采用列表特有的列表切片进行操作,再将列表进行组合
A = A[k:] + A[:k]
# 返回移动之后的列表
return A
k = int(input("请输入向左移的位数:"))
n = int(input("数组A的元素个数:"))
print("请输入元素:")
A = [input() for i in range(n)]
print("移动之前:" + "".join(A))
print("移动之后:" + "".join(rv(A, k)))
2. 设a1,a2,…,an是集合{1,2,3,…,n}的一个全排列,如果i<j且ai>aj,则序偶(ai,aj)称为该排列的一个逆序。例如,2,3,1有两个逆序:(3,1)和(2,1)。设计算法统计给定排序中含有逆序的个数。
def nx(a):
# 获取列表a的长度
l = len(a)
# 定义一个空列表用来存储逆序列
b = []
# 指针i指向a中的元素
for i in range(l-1):
# 指针k指向指针i后面的元素
for j in range(i+1, l):
# 判断指针i和j指向的元素是否满足逆序的条件
if a[i] > a[j]:
# 满足添加到列表b中
c = (a[i], a[j])
b.append(c)
# 返回所有满足的逆序
return b
n = int(input("请输入列表的元素个数:"))
print("请输入列表元素:")
a = [int(input()) for i in range(n)]
print("逆序有:{},一共有{}个。".format(nx(a), len(nx(a))))
实验四
1. 设计折半查找算法,在有序序列{7,14,18,21,23,29,31,35,38}中查找18。
def zb(a, k):
# 定义双指针进行位置的确定(首和尾)
i = 0
j = len(a) - 1
# 开始遍历数组,当两指针指向同一个数时终止循环
while(i <= j):
# 找到两指针的中间位置(注意有可能为小数,进行取整)
mid = (i + j) // 2
# 对目标值的位置进行判断
if k < a[mid]:
j = mid - 1
elif k > a[mid]:
i = mid + 1
else:
return mid + 1
# 返回最终值的位置
return i-1
n = int(input("请输入数组的个数:"))
k = int(input("查找的元素:"))
print("请输入数组中的{}个数:".format(n))
a = [int(input()) for i in range(n)]
m = zb(a, k)
print("您需要查找的数{}在数组中的位置为{}".format(k, m))
2. 修改折半查找算法使之能够进行范围查找。所谓范围查找是要在找出给定值a和b之间的所有元素(a小于等于b)
def zb(a, x, y):
# 列表结果存储
o = []
# 定义双指针进行位置的确定(首和尾)
i = 0
j = len(a) - 1
# 开始遍历数组,当两指针指向同一个数时终止循环
while(i <= j):
# 找到两指针的中间位置(注意有可能为小数,进行取整)
mid = (i + j) // 2
# 对目标值的位置进行判断
if y < a[mid]:
j = mid - 1
elif x > a[mid]:
i = mid + 1
else:
# 因为此时中间数是范围中的,因此在此处直接进行添加在列表结果中
for k in range(i,j):
if x<= a[k] <= y:
o.append(k)
return o
n = int(input("请输入数组的个数:"))
print("请输入范围:")
x = int(input())
y = int(input())
print("请输入数组中的{}个数:".format(n))
a = [int(input()) for i in range(n)]
m = zb(a, x, y)
print("范围在{}到{}在数组中的位置是从{}到{}".format(x, y, m[0], m[1]))
print("数组中的数分别为:", end = '')
for i in m:
print(a[i], end = ' ')
实验五
1 设有n个顾客同时等待一项目服务,顾客i 需要的服务时间为ti(1≤i≤n)
,如何安排n个顾客的服务次序才能使顾客总的等待时间达到最小?
def jy(n, x):
# 加油的次数
count = 0
# 汽车的剩余油量
y = n
# 开始行使
for i in range(len(x)-1):
# 到达一个加油站
y -= x[i]
# 判断是否需要加油
if y > x[i+1]:
# 不需要,继续走
continue
else:
# 需要,输出这是第几个加油站,并统计加油一次
print(f"这个是第{i+1}个加油站")
count += 1
# 加满油
y = n
# 输出加油的次数
return count
n = int(input("请输入加满油之后车能跑多远:"))
k = int(input("请输入有多少个加油站:"))
print("请输入距离:")
x = [int(input()) for i in range(k+1)]
print(f"总共加油次数:{jy(n,x)}")
2 在0/1背包问题中,假设各物品按重量递增排列时,其价值恰好按递减排列,对于这个特殊的0/1背包问题,设计一个有效的算法找出最优解。
# 从键盘输入中得到物品的体积和价值
def qu(N):
for i in range(N):
x = [int(j) for j in input().split()]
v.append(x[0])
w.append(x[1])
return v, w
# 获取最大的价值
def max_():
for i in range(1, n+1): # 有几个物品可供选择
for j in range(1, m + 1): # 模拟背包容量从m+1
if j < v[i-1]: # 如果此时背包容量小于当前物品重量
f[i][j] = f[i - 1][j] # 不拿这个物品
else:
# 此时有两种选择,拿或不拿
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i - 1]] + w[i-1])
# 选择最好的一种方式,也就是两种情况作比较,取价值的较大值
# 取得物品的个数和背包的总体积
a = [int(i) for i in input().split()]
# 物品的个数
n = a[0]
# 背包总体积
m = a[1]
# 各个物品的体积列表
v = []
# 对应物品的价值
w = []
# 将物品的体积和价值装入列表中
qu(n)
# 模拟背包
f = [[0] * (m + 1) for _ in range(n + 1)]
# 获取最大的价值
max_()
print(f[n][m])
3 一辆汽车加满油后可行驶n公里,旅途中若干个加油站,加油站之间的距离由数据A[m]给出,其中A[i]表示第i-1个加油站和第i个加油站的距离,旅途的起点和终点都各有一个加油站。设计一个有效的算法,计算沿途需要停靠加油的地方,使加油次数最少。
def sj(t):
# 列表存储每一位顾客的等待时间
a = [0 for i in range(len(t))]
# 将顾客等待时间按照时间进行排序
t = sorted(t, key = lambda x:x[0])
# 遍历顾客时间,并对每一位顾客的时间进行累加
for i in range(len(t)):
# 输出每次进行服务的顾客是第几位
print("第{}次服务第{}个顾客。".format(i+1,t[i][1]+1))
for j in range(i,len(t)):
a[j] += t[i][0]
# 返回最后的总时间
return sum(a)
# 输入顾客的数量
n = int(input("请输入顾客的人数:"))
print("请输入每个顾客服务的时间:")
# 输入每一个顾客进入的次序和服务时间
t = [[int(input()),i] for i in range(n)]
# 进行统计总的等待时间
tz = sj(t)
# 输出平均时间
print("顾客平均等待时间:",tz/n)
实验六
1. 跳跃游戏II
class Solution(object):
def jump(self, nums):
# 设置初始的值
m, n, t, = 0, 0, 0
# 开始遍历,贪心每次找到局部最优,通过局部最优找到全局最优
# 遍历时不访问最后一个元素
for i in range(len(nums) - 1):
if m >= i:
m = max(m, i + nums[i])
if i == n:
n = m
t += 1
return t
2. 买卖股票的最佳时机
class Solution:
def maxProfit(self, prices):
# 定义无穷最低价格为无穷大
minprice = int(1e9)
# 初始化最大利润为0
maxlr = 0
# 循环遍历一次价格列表
for price in prices:
# 判断此时对应的利润与最大利润大小,选取大的利润
maxlr = max(price - minprice, maxlr)
# 比较现在的价格的以前的价格大小
minprice = min(price, minprice)
# 因为是从开始到结束一遍结束,因此输出最大利润即可
return maxlr
实验七
1. 爬楼题
class Solution:
def climbStairs(self, n: int) -> int:
# 如果n小于三直接输出n
if n <= 3:
return n
# 初始定义两个初值
a, b = 2, 3
# 每一次进行交换
for i in range(2,n):
a, b = b, a+b
# 返回计算得出的值
return a
2. 硬币
# 硬币
class Solution:
def waysToChange(self, n: int) -> int:
mod = 10**9 + 7
coins = [25, 10, 5, 1]
f = [1] + [0] * n
for coin in coins:
for i in range(coin, n + 1):
f[i] += f[i - coin]
return f[n] % mod
实验八
1. 有面值为(v1, v1, ..., vn )的n种纸币,需要支付y值的纸币,应如何支付才能使纸币支付的张数最少,即满足i=1nxivi=y
,且使i=1nxi
最小。设计动态规划算法求解付款问题。
n = int(input("请输入货币种类的个数:"))
print("从小到大输入货币的价值,其中第一个必须为一")
h = [0] + [int(input()) for i in range(1, n+1)]
z = int(input("输入要兑换的钱的价值:"))
a = [[0] * (n+1) for _ in range((z+1))]
for i in range(1, z+1):
for j in range(1, n+1):
if h[j] == i:
a[i][j] = 1
elif h[j] > i:
a[i][j] = a[i][j - 1]
else:
a[i][j] = a[i - h[j]][j] + 1
print(f"兑换的最小货币张数是:{a[z][n]}")
2. 给定一个正整数集合X={x1, x2, ... , xn}和一个正整数y,设计回溯算法,求集合X的一个子集Y,使得Y中元素之和等于y。
def ziji(X, y):
i = 0
# 存储目标子集
Y = []
while i < len(X):
# 开始遍历全集
j = i
# 将产生出来的所有子集进行存储
yi = []
# 开始遍历
for k in range(j, len(X)):
# 将现有的子集放入子集列表中
yi.append(X[k])
# 如果刚好等于我们需要计算得出的数,直接将此子集进行存储,终止此次循环
if sum(yi) == y:
Y.append(yi)
break
# 如果大于我们需要计算的数,则也终止此次循环
if sum(yi) > y:
break
# 继续往后面走
i += 1
return Y
n = int(input("请输入集合元素的个数:"))
X = [int(input()) for i in range(n)]
y = int(input("请输入求和的结果为:"))
Y = ziji(X, y)
print(f"所有子集为:{Y}")
3. 桥本分数。把{1,2,…,9}这九个数字填入下图所示的9个方格中,使得等式成立,要求数字不得重复。
# 将输入的数列表进行全排列,并输出全排列
def qpl(nums):
res = []
def back(nums_all, temp):
if len(nums_all) == 0:
res.append(temp)
return
for i in range(len(nums_all)):
back(nums_all[:i] + nums_all[i + 1:], temp + [nums_all[i]])
t = []
back(nums, t)
return res
# 输入1到9
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 得到全排列的结果
x = qpl(a)
y = []
# 将除法转换为乘法
for i in x:
# 防止出现3+7=10,7+3=10的情况
if i[0] < i[3]:
x1, x2 = i[0], i[1] * 10 + i[2]
y1, y2 = i[3], i[4] * 10 + i[5]
z1, z2 = i[6], i[7] * 10 + i[8]
# 满足相等的情况则将信息存入
if x1 * y2 * z2 + x2 * y1 * z2 == x2 * y2 * z1:
y.append(i)
# 输出最后的结果
print(f"解的个数为:{len(y)}")
for i in range(len(y)):
print(f"第{i + 1}个解为:{y[i]}")
4 设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设wij是从供应商j 处购得的部件i的重量,cij
是相应的价格。试设计一个回溯算法,给出总价格不超过d的最小重量机器设计。对于给定的机器部件重量和机器部件价格,计算总价格不超过d的最小重量机器设计。
def hs(t):
# 定义全局变量,防止在回溯过程中重复定义
global n, m, w, v, min_w, min_v, best_w, best_v, best_x
if t >= n:
# 条件更优时,更新数据
if min_v <= d and min_w < best_w:
best_w, best_v = min_w, min_v
for j in range(n):
best_x[j] = x[j]
else:
for j in range(m):
# 记录下当前部件是哪一个供应商
x[t] = j
min_w = min_w + w[t][j]
min_v = min_v + v[t][j]
# 剪枝
if min_v <= d and min_w < best_w:
# 如果当前供应商的部件可以满足条件 直接进入下一个部件的判断
hs(t + 1)
# 回溯过程
min_w = min_w - w[t][j]
min_v = min_v - v[t][j]
return best_w, best_x
# 输入机器部件数、供应商数、计算总价值不超过d的值
n, m, d = [int(i) for i in input("请输入机器部件数、供应商数、计算总价值不超过d的值:").split()]
# 各表示从供应商j处购得部件i的价格/重量
v = [[int(i) for i in input().split()] for _ in range(n)]
w = [[int(i) for i in input().split()] for _ in range(n)]
# 定义存储当前最小的重量和价值的变量
min_w, min_v = 0, 0
# 定义最优的最小重量和价值(初始化为999)
best_w, best_v = 999, 999
# 定义存储提供部件的供应商以及最优供应商
x, best_x = [0 for _ in range(m)], [0 for _ in range(m)]
hs(0)
print(f"最优重量:{best_w},最优的供应商:{[i+1 for i in best_x]}")
一个机器人只能向下和向右移动,每次只能移动一步,设计一个算法求机器人从(0,0)到(m,n)有多少条路径。
def lj(n, m):
# 利用回溯法进行不断的获取路径
if n == 1 and m == 1:
return 1
elif n == 1:
return lj(n, m - 1)
elif m == 1:
return lj(n - 1, m)
else:
return lj(n - 1, m) + lj(n, m - 1)
n = int(input("请输入n:"))
m = int(input("请输入m:"))
print(f"机器人从(0,0)到(m,n)有:{lj(n, m)}条路径")