本大白最近带一只小白入手编程,想法是在练习中学习,所以弄了几个题目。其中不少是经典的练习题,在很多编程入门书籍中都有出现;有的题涉及到一点数据结构的理念。在这里分享出来,刚接触编程的同学可以和我们一起做一做(无论学的是哪种语言都可以看一看,思路是通用的。这里我们学的是python),也欢迎大家指正。
有时需要用到整数1-n的随机排列,如决定出场顺序等。
整数1-n的排列,共n!种,所以我们的目的相当于是从n!个样本点构成的总体中,随机等概率地抽取一个样本点。
当然,我们的实现算法不采取上述的n!的方式,需要采用计算量合理的算法。
一个可能出现的误区是:不断地产生1~n之间的随机整数;如果遇到与已经产生的整数出现重复,则舍弃掉这个整数,并继续产生,一直到产生n个不同的整数(>=1, <=n)。这个方法简单也直观,但从概率的角度看,这样产生的结果与上述的随机等概率抽样并不等价。
这里采用一种比较简单的方法:让计算机产生n个0~1均匀分布的随机数(一般我们使用的n较小,那么计算机产生的这n个随机并不重复),得到一个随机数序列。按顺序记录着n个随机数,即为每一个随机数贴上“标签”,标签上记录的是它在这个序列中的序号。
然后对这n个随机数排序。排序之后,随机数的位置自然发生了变换,我们按现在的位置顺序把它们的“标签”取出来,就得到一个1-n整数的随机排列。
import random
def random_permutation(n):
key_value = {}
random_number = []
permutation = []
for i in range(n):
r = random.uniform(0, 1)
key_value[r] = i + 1
random_number.append(r)
random_number.sort()
for i in range(n):
r = random_number[i]
permutation.append(key_value[r])
return permutation
# 例
random_permutation(21)
(关于这个问题,我弄了一个小界面,链接:java简单实现整数的随机重排)
平面直角坐标系中,一个醉汉从原点出发,跌跌撞撞地走,每一步的方向和步长是随意的。我们可以产生两个服从(0, 1)均匀分布的随机数dx,dy代表每一步在x方向和y方向的变化。
我们可以定义一个类RandomWalk,构造方法指定步数,默认走1000步;walk()方法完成游走,get_x()、get_y()方法返回当前坐标。
import random
# class
class RandomWalk():
def __init__(self, steps=1000):
self.steps = steps
self.x = [0]
self.y = [0]
def walk(self):
counts = 0
while counts < self.steps:
dx = random.uniform(-1, 1)
dy = random.uniform(-1, 1)
if dx == 0 and dy == 0:
continue
self.x.append(self.x[-1] + dx)
self.y.append(self.y[-1] + dy)
counts += 1
def get_x(self):
return self.x
def get_y(self):
return self.y
# plot
import matplotlib.pyplot as plt
stumbler = RandomWalk()
stumbler.walk()
x = stumbler.get_x()
y = stumbler.get_y()
plt.plot(x, y, color='grey')
plt.plot(x[0], y[0], marker='o', markerfacecolor='blue')
plt.plot(x[-1], y[-1], marker='o', markerfacecolor='red')
plt.show()
一次模拟的路径如图所示
斐波拉契额数列:1, 1, 2, 3, 5, 8, 13, 21, ... 从第三项起,每一项为前两项之和。
函数f(n)返回斐波拉契数列的第n项。
法一:递归法。这样定义:若n等于1或2,返回1;否则返回f(n-1)+f(n-2)。
但是这样的递归法产生了大量的重复计算,效率十分低。
法二:动态法。通过两个动态的变量完成计算。
### 21.1 递归法(不好)
n = int(input("Enter an integer: "))
print("The first " + str(n) + "th numbers in Fibonacci are: ")
for i in range(1, n + 1):
print(str(fibonacci_2(i)) + ' ', end = '')
def fibonacci_2(n):
if n == 1 or n == 2:
return 1
else:
return fibonacci_2(n - 1) + fibonacci_2(n - 2)
### 21.2 动态法
n = int(input("Enter an integer: "))
print("The first " + str(n) + "th numbers in Fibonacci are: ")
for i in range(1, n + 1):
print(str(fibonacci_1(i)) + ' ', end = '')
def fibonacci_1(n):
temp1 = 0
temp2 = 1
for i in range(n):
result = temp2
temp = temp2
temp2 += temp1
temp1 = temp
return result
古时候有三个底座A,B,C,A座上放有若干个大小均不相同的盘子,且大盘在下小盘在上。现在想将A座上的所有盘子移动到C座上,但要求:每次只能移动一个盘子;转移过程中都必须大盘在下小盘在上;可以借助B座。
如移动3个盘子的过程:
这个问题不用递归的方法是十分困难的。若A座初始时只有一个盘子,则问题迎刃而解;若A座初始时有n个盘子,可以这样考虑:借助C座将A座的前n-1一个盘子移向B座(怎样完成这个移动交给递归去解决),这样A座只剩一个最大的盘子,将其直接移向C座,然后借助A座将B座的n-1个盘子移向C座(怎样完成这个移动交给递归去解决),于是任务完成。
n = int(input("Enter the number of dishes: "))
hanoi(n, 'A', 'B', 'C')
def hanoi(n, A, B, C):
if n == 1:
print("Move " + str(n) + " from " + A + " to " + C)
else:
hanoi(n-1, A, C, B)
print("Move " + str(n) + " from " + A + " to " + C)
hanoi(n-1, B, A, C)
在一个数字各不相同的列表中,我们想寻找目标数,即定位目标数所在位置。
若列表中数字排列无序,我们可以“一个一个”地查找,即线性查找。
若列表中数字已由小到大排序,我们可以先看中间位置的数等于、或大于、或小于目标数,若等于则完成查找;若大于则查找前部;若小于则查找后部,即二分查找。若列表中数字已排序,则二分查找的效率(O(log(n))高出线性查找(O(n))许多。
对于二分查找是一个递归的过程,所以也可用递归的方法实现。
### 23.1 线性查找
def search(number_list, key):
for i in range(len(number_list)):
if number_list[i] == key:
return i
return -1
# 例
x = [2, 4, 6, 8, 10, 13, 17, 19, 20, 25]
search(x, 1)
search(x, 2)
search(x, 3)
search(x, 4)
search(x, 5)
search(x, 6)
search(x, 13)
search(x, 21)
search(x, 25)
search(x, 26)
### 23.2 二分查找
def search_binary(number_list, key):
low = 0
high = len(number_list) - 1
while low <= high:
mid = int((low + high) / 2)
if number_list[mid] == key:
return mid
elif number_list[mid] > key:
high = mid - 1
elif number_list[mid] < key:
low = mid + 1
return -low - 1
# 例
x = [0, 1, 2, 3, 4, 5]
search_binary(x, -1)
search_binary(x, 0)
search_binary(x, 0.5)
search_binary(x, 1)
search_binary(x, 1.5)
search_binary(x, 2)
search_binary(x, 2.5)
search_binary(x, 3)
search_binary(x, 3.5)
search_binary(x, 4)
search_binary(x, 4.5)
search_binary(x, 5)
search_binary(x, 6)
### 23.3 递归的二分查找
def search_binary_recursive(number_list, key, low, high):
if low > high:
return -low - 1
mid = int((low + high) / 2)
if number_list[mid] == key:
return mid
elif number_list[mid] > key:
return search_binary_recursive(number_list, key, low, mid-1)
elif number_list[mid] < key:
return search_binary_recursive(number_list, key, mid+1, high)
# 例
x = [0, 1, 2, 3, 4, 5]
search_binary_recursive(x, -1, 0, len(x)-1)
search_binary_recursive(x, 0, 0, len(x)-1)
search_binary_recursive(x, 0.5, 0, len(x)-1)
search_binary_recursive(x, 1, 0, len(x)-1)
search_binary_recursive(x, 5, 0, len(x)-1)
search_binary_recursive(x, 6, 0, len(x)-1)
后续部分请见 刚接触编程的同学可以看看的几个编程练习(python实现)(五)