数组
数组(Array)是有序的元素序列,组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。可以说,数组是最常见的数据结构了,也是出题时能玩出花来的一种类型。它和数学,排序息息相关,实际上我们在offer01-03中已经数次见到它们了。
《剑指offer》01&02、数组中的重复数
《剑指offer》03、二维数组的检索
而offer10和18也是和数组、排序相关的。
旋转数组的最小值
offer10的要求是,给定一个非严格递增数组的一个旋转,求这个数组的最小元素。
num = [int(n) for n in input().split()]
所谓旋转,比如数组
[1,2,3,4,5,6],它的一个旋转就是[3,4,5,6,1,2];简单地理解,就是将前n个元素整段抽出来拼在数组的后面。非严格递增的情况下,比如[0,0,1,1,1,1,2],它的一个旋转是[1,1,1,2,0,0,1],另一个旋转是[1,2,0,0,1,1,1]。这个概念还是好理解的。
首先,非常好理解的方式就是一次遍历,时间复杂度O(n)
# offer10-solution 1
def MinNUMinRotatedArray01(num):
start = num[0]
for i in range(1, len(num), 1):
if num[i] < start:
print(num[i])
return
print(start)
return
MinNUMinRotatedArray01(num)
以及,很容易想到的二分查找法。
二分查找需要设置一个头指针,尾指针和中间指针,通过中间指针的摇摆,判断最小值在数组的哪一部分,从而达到缩小搜索范围的目的。需要注意的是:当旋转数组的两端点的值都与中间点的值相等时,无法判断最小值在哪一部分,这时候还是需要采用顺序查找。
# offer10-solution 2
def MinNUMinRotatedArray02(num):
length = len(num)
start, mid, end = 0, 0, length-1
while True:
# 如果出现头指针,中指针,尾指针对应的值相同,就无法二分查找,要遍历
if (num[start] == num[mid]) and (num[mid] == num[end]):
# 偷懒直接应用之前的题解
MinNUMinRotatedArray01(num)
return
if end - start == 1: # 二分查找到头指针和尾指针相邻时结束
mid = end
break
# 改写中间指针
mid = int((start + end) / 2)
if num[start] <= num[mid]:
start = mid
elif num[end] >= num[mid]:
end = mid
print(num[mid])
return
MinNUMinRotatedArray02(num)
关于二分查找,文末有个blog我个人感觉是不错的。
重排数组
offer18的要求是,给出一个数组 [ x 1 , x 2 , … x n , y 1 , y 2 , … y n ] {\left[x_{1}, x_{2}, \ldots x_{n}, y_{1}, y_{2}, \ldots y_{n}\right]} [x1,x2,…xn,y1,y2,…yn],要求将其重新排列成 [ x 1 , y 1 , x 2 , y 2 , … x n , y n ] {\left[x_{1}, y_{1}, x_{2}, y_{2}, \ldots x_{n}, y_{n}\right]} [x1,y1,x2,y2,…xn,yn]。
num = [int(n) for n in input().split()]
很容易想到利用append的一次遍历,时间和空间复杂度都是O(n),我一开始还想复杂了……
# offer18-solution
def reOrderArray(num):
n = int(len(num) / 2)
res = []
for i in range(0, n, 1):
res.append(num[i])
res.append(num[i+n])
print(res)
return
reOrderArray(num)