1. 程式人生 > >劍指offer系列(十二)最小的k個數, 連續子陣列的最大和,整數中1出現的個數

劍指offer系列(十二)最小的k個數, 連續子陣列的最大和,整數中1出現的個數

最小的k個數

題目描述

輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,。

解題思路:

思路1,這一題應用堆排序演算法複雜度只有O(nlog 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儲存最大值並隨時更新。也可以利用動態規劃解決。

程式碼:

# -*- 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 
           
                    

整數中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)

C++版程式碼實現

程式碼:

法一:

# -*- 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