《剑指Offer》专题: 第五期 41-50
这里是《剑指Offer》专题系列第五期,一共十题,每题对应多种解法,一起来看看吧。
###正文
题目41:和为S的连续正数序列
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
"""
方法1:利用数学方法 时间复杂度O(sqrt(n))
方法2:滑动窗口法,时间复杂度O(sqrt(n))
"""
class Solution:
def FindContinuousSequence(self, tsum):
#方法1:数学规律
"""
# 鲁棒性代码
if tsum <=0: return []
res = []
temp = []
x = int((2*tsum)**0.5)# 等差数列求和公式得出 n<sqrt(2*sum)
for n in range(x,1,-1): #n为序列的长度,范围为了减少n扫描的次数
#n为偶数和n为奇数时,满足以下条件才能组成连续和S
if tsum%n==0.5*n or ((n%2) and (tsum%n==0)):
for i in range(tsum/n-(n-1)/2,tsum/n+n/2+1):
temp.append(i)
res.append(temp)
temp = []
return res
"""
#方法2: 滑动窗口法(不定长,可伸缩)
l, r, sum, res = 1, 2, 3, []
while l<r and l<2*tsum**0.5:# l<2*tsum**0.5是从方法1偷师来的,加上会减少时间复杂度
if sum>tsum:#如果大了,则把最前面的从窗口中去掉
sum -= l
l += 1 #左边标志右移
else:
if sum==tsum:#相等则加入返回列表
res.append([i for i in range(l,r+1)])
r += 1 #窗口右移
sum += r
return res
####题目42:和为S的两个数字
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出
# -*- coding:utf-8 -*-
"""
方法1: 时间复杂度o(n),空间复杂度o(1)
利用数学知识:我们知道两个数的和固定时,两个数越接近,则乘积越大,反之,乘积越小
于是,我们定义两个指针small,large,一个从第0位开始递增,一个从最后一位开始递减
当满足两个位置的数字之和等于tsum,则跳出循环,并返回这两个位置的值,此时乘积一定是最小的。
如果当small>=large时,退出循环,此时未找到两个数之和等于tsum,返回空数组。
"""
class Solution:
def FindNumbersWithSum(self, array, tsum):
# write code here
if not array:return []
small, large = 0, len(array)-1
result =[]
while small<large: #
if array[small]+array[large]== tsum:
result = [array[small],array[large]]
break
elif array[small]+array[large]<tsum: