问题描述
给定一个正整数 n,定义一次"增殖"操作如下:
- 将数字
n转化为一个包含1到n的递增序列 - 例如:当
n = 4时,一次增殖后变为序列[1, 2, 3, 4]
现给定三个正整数:
- 初始数字
n - 增殖次数
k - 位置索引
p(从1开始计数) 请计算经过k次增殖操作后,序列中第p个位置的数字。如果p超出序列长度,则返回-1。
样例
输入:
n = 4 ,k = 3 ,p = 19
输出:3
解释:
第1次增殖:4 -> [1,2,3,4]
第2次增殖:[1,2,3,4] -> [1, 1,2, 1,2,3, 1,2,3,4]
第3次增殖:得到最终序列 [1, 1, 1,2, 1, 1,2, 1,2,3, 1, 1,2, 1,2,3, 1,2,(3),4] -> ,第19个位置的数字是3
分析
由题意可知,每次增殖都会将正整数n转化为 [1, 2, ..., n],并将这些序列拼接起来,每次增殖操作会将当前的序列转化为一个更长的序列。
据此,我们选用列表。
- 先定义一个函数,实现将数字
n转化为一个包含1到n的递增序列。
def to_list(a):
a_list = []
for i in range(1,a + 1):
a_list.append(i)
return a_list
这里,我们定义一个空列表a_list[],使用append方法,配合for...range返回一个递增序列。注意是1~n。
- 接着我们实现
k次增殖操作。
def solution(n, k, p):
b_list = to_list(n)
for x in range(2,k + 1):
c_list = []
for y in b_list:
c_list += to_list(y)
b_list = c_list
在这部分,我们使用b_list = to_list(n)先增殖一次,获取一个列表,这样方便后续使用for循环。定义一个空列表c_list = [],通过c_list += to_list(y)将遍历时每个元素增值后的结果合并在一起,然后更新b_list,这便是最终结果。
- 输出
if p > len(b_list):
return -1
else:
return b_list[p - 1]
在输出结果之前,检查一下p 是否超出我们获得的最终列表长度,如果超出,return -1,如果没有,return b_list[p - 1]。(因为我们需要的是第p个数字,而列表的下标是从0开始的,所以我们需要的是下标为p - 1的元素。
- 测试
def to_list(a):
a_list = []
for i in range(1,a + 1):
a_list.append(i)
return a_list
def solution(n, k, p):
b_list = to_list(n)
for x in range(2,k + 1):
c_list = []
for y in b_list:
c_list += to_list(y)
b_list = c_list
if p > len(b_list):
return -1
else:
return b_list[p - 1]
if __name__ == "__main__":
print(solution(4, 3, 19) == 3)
运行成功且结果正确。
总结、优化
以上示例的代码只是一个比较直接的方法。这个方法会在增殖次数较大时,产生大量的计算(我们生成了列表)。仔细思考我们会发现,每次增殖后,列表元素数量是可知的,那么我们只需要计算包含第p个元素的列表就行,这将免去不必要的计算。
- 以下是优化后的示例代码
def solution(n, k, p):
# 计算前 k 次增殖操作后的序列长度
def calculate_length(n, k):
length = 0
for i in range(1, n + 1):
length += i ** k
return length
# 计算第 p 个位置的数字
def find_position(n, k, p):
current_length = 0
for i in range(1, n + 1):
next_length = current_length + i ** k
if p <= next_length:
return i
current_length = next_length
return -1
# 计算序列长度
total_length = calculate_length(n, k)
# 检查 p 是否超出序列长度
if p > total_length:
return -1
# 找到第 p 个位置的数字
return find_position(n, k, p)