刚接触编程的同学可以看看的几个编程练习(python实现)(四)

本大白最近带一只小白入手编程,想法是在练习中学习,所以弄了几个题目。其中不少是经典的练习题,在很多编程入门书籍中都有出现;有的题涉及到一点数据结构的理念。在这里分享出来,刚接触编程的同学可以和我们一起做一做(无论学的是哪种语言都可以看一看,思路是通用的。这里我们学的是python),也欢迎大家指正。

19. 整数重排

有时需要用到整数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简单实现整数的随机重排)

20. 随机游走

平面直角坐标系中,一个醉汉从原点出发,跌跌撞撞地走,每一步的方向和步长是随意的。我们可以产生两个服从(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()

一次模拟的路径如图所示

刚接触编程的同学可以看看的几个编程练习(python实现)(四)_第1张图片

21. 斐波拉契数列

斐波拉契额数列: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 

22. 汉诺塔

古时候有三个底座A,B,C,A座上放有若干个大小均不相同的盘子,且大盘在下小盘在上。现在想将A座上的所有盘子移动到C座上,但要求:每次只能移动一个盘子;转移过程中都必须大盘在下小盘在上;可以借助B座。

如移动3个盘子的过程:

刚接触编程的同学可以看看的几个编程练习(python实现)(四)_第2张图片

这个问题不用递归的方法是十分困难的。若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)

23. 查找

在一个数字各不相同的列表中,我们想寻找目标数,即定位目标数所在位置。

若列表中数字排列无序,我们可以“一个一个”地查找,即线性查找。

若列表中数字已由小到大排序,我们可以先看中间位置的数等于、或大于、或小于目标数,若等于则完成查找;若大于则查找前部;若小于则查找后部,即二分查找。若列表中数字已排序,则二分查找的效率(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实现)(五)

你可能感兴趣的:(python)