最小的k个数
题目描述
输入n个整数,找出其中最小的K个数。(不是topk问题!!,topk是最大的k个数。)例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
解题思路:
思路1,这一题应用堆排序算法复杂度只有O(n*log k)(阿里,微软等面试常考!!!)n个数,每次调整堆时间复杂度是logk,故总时间复杂度O(n*log k),堆是完全二叉树的一种,最大堆就是最上面的数是最大的,该方法基于二叉树或者堆来实现,首先把数组前k个数字构建一个最大堆,然后从第k+1个数字开始遍历数组,如果遍历到的元素小于堆顶的数字,那么就交换这两个数字,重新构造堆,继续遍历,最后剩下的堆就是最小的k个数,时间复杂度O(nlog k)。
思路2:排序
附:
heapq模块提供了如下几个函数:
heapq.heappush(heap, item) 把item添加到heap中(heap是一个列表)
heapq.heappop(heap) 把堆顶元素弹出,返回的就是堆顶
heapq.heappushpop(heap, item) 先把item加入到堆中,然后再pop,比heappush()再heappop()要快得多
heapq.heapreplace(heap, item) 先pop,然后再把item加入到堆中,比heappop()再heappush()要快得多
heapq.heapify(x) 将列表x进行堆调整,默认的是小顶堆
heapq.merge(*iterables) 将多个列表合并,并进行堆调整,返回的是合并后的列表的迭代器
heapq.nlargest(n, iterable, key=None) 返回最大的n个元素(Top-K问题)
heapq.nsmallest(n, iterable, key=None) 返回最小的n个元素(Top-K问题)
代码:
方法一:
# -*- coding:utf-8 -*-
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
import heapq #堆
if tinput == None or len(tinput)<k or len(tinput)<=0 or k <=0:
return []
return heapq.nsmallest(k, tinput)
方法二:
# -*- coding:utf-8 -*-
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
import heapq
if tinput == None or len(tinput)<k or len(tinput)<=0 or k<=0:
return []
return sorted(tinput)[:k]
连续子数组的最大和
题目描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
解题思路:
对于连续子数组,可以用一个数值来存储当前和,如果当前和小于零,那么在进行到下一个元素的时候,直接把当前和赋值为下
一个元素,如果当前和大于零,则累加下一个元素,同时用一个maxNum存储最大值并随时更新。
利用动态规划解决:假设sum[i]表示以第i个元素结尾的最大连续字串,那么sum[i]=max{sum[i-1]+a[i],a[i]},判断括号中的元素哪个大,就变成了判断sum[i-1]是否大于0。DP[i] = max{DP[i-1] + A[i],A[i]}
代码:
方法一:非动态规划
# -*- coding:utf-8 -*-
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
if array ==None or len(array)<=0:
return 0
sum = 0
result = array[0]
for i in range(len(array)):
if sum<=0:
sum = array[i]
else:
sum += array[i]
if sum>result:
result = sum
return result
方法二:动态规划
# -*- coding:utf-8 -*-
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
res =max(array)
temp = 0
for i in array:
temp = max(i,temp+i)
res = max(res,temp)
return res
整数中1出现的个数
题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
解题思路:
法一:将1-n全部转换为字符串,只需要统计每个字符串中'1'出现的次数并相加即可
法二:从1到n遍历,每次通过对10求余数判断整数的个位数字是不是1,大于10的除以10之后再判断。我们对每个数字都要做除法和求余运算以求出该数字中1出现的次数。如果输入数字n,n有O(logn)位,我们需要判断每一位是不是1,那么时间复杂度为O(n*logn)。
法三:
数学之美上面提出的方法,设定整数点(如1、10、100等等)作为位置点i(对应n的各位、十位、百位等等),分别对每个数位上有多少包含1的点进行分析。
- 根据设定的整数位置,对n进行分割,分为两部分,高位n/i,低位n%i
- 当i表示百位,且百位对应的数>=2,如n=31456,i=100,则a=314,b=56,此时百位为1的次数有a/10+1=32(最高两位0~31),每一次都包含100个连续的点,即共有(a/10+1)*100个点的百位为1
- 当i表示百位,且百位对应的数为1,如n=31156,i=100,则a=311,b=56,此时百位对应的就是1,则共有a/10(最高两位0-30)次是包含100个连续点,当最高两位为31(即a=311),本次只对应局部点00~56,共b+1次,所有点加起来共有(a/10*100)+(b+1),这些点百位对应为1
- 当i表示百位,且百位对应的数为0,如n=31056,i=100,则a=310,b=56,此时百位为1的次数有a/10=31(最高两位0~30)
- 综合以上三种情况,当百位对应0或>=2时,有(a+8)/10次包含所有100个点,还有当百位为1(a%10==1),需要增加局部点b+1
- 之所以补8,是因为当百位为0,则a/10==(a+8)/10,当百位>=2,补8会产生进位位,效果等同于(a/10+1)
代码:
法一:
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
# write code here
count = 0
for i in range(1, n+1):
for i in str(i):
if i =='1':
count += 1
return count
法二:
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
# write code here
count = 0
for i in range(0, n+1):
temp = i
while temp :
if temp%10 ==1:
count +=1
temp /=10
return count
法三:
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
# write code here
count = 0
i = 1
while i<=n:
count +=(n//i+8)//10*i+(n//i%10==1)*(n%i+1)
i *=10
return count