2019年8月20日

過擬合專題

過擬合的緣由:node

  1. 訓練集的數量級要小於模型的複雜度;
  2. 訓練集和測試集特徵分佈不一致;
  3. 樣本里的噪音數據干擾過大;
  4. 權值學習迭代次數足夠多(Overtraining)。

過擬合的解決方案:python

  • 數據層面:增長數據,數據加強
  • 模型層面:合適的模型(參數量較小),權重衰減(正則化),噪聲(包括權重噪聲和輸入噪聲),訓練早停,模型剪枝, 激活函數選擇Relu
  • 集成學習:bagging,boosting,dropout

大數據專題

大數據排序

方法一: bitmap排序(要求無重複數據)算法

bitmap就是每一位存一個數字,一個byte有8個bit,能夠存8個數據。1M內存能夠存:8x1024X1024 = 8,388,608的數據。 api

而後順序遍歷bitmap便可取出排好序的數據。

#Bitmap
class Bitmap():
    def __init__(self,max):
        '肯定所需數組個數'
        self.size = int ((max + 31 - 1) / 31)
        self.array = [0 for i in range(self.size)]

    def bitindex(self,num):
        '肯定數組中元素的位索引'
        return num % 31

    def set(self,num):
        '將元素所在的位置1'
        elemindex = num // 31
        byteindex = self.bitindex(num)
        ele = self.array[elemindex]
        self.array[elemindex] = ele | (1 << byteindex)

    def test(self,i):
        '檢測元素存在的位置'
        elemindex = i // 31
        byteindex = self.bitindex(i)
        if self.array[elemindex] & (1 << byteindex):
            return True
        return False

if __name__ == '__main__':
    Max = 110
    suffle_array = [51, 100 ,2, 4, 34]
    result = []
    bitmap = Bitmap(Max)
    for c in suffle_array:
        bitmap.set(c)
    for i in range(Max+1):
        if bitmap.test(i):
            result.append(i)
            
    print('原始數組爲: %s' % suffle_array)
    print('排序後的數組爲: %s' % result)
複製代碼

大數據TopK

題目:從1億個整數裏找出100個最大的數 方法一:堆排序數組

  • 1.讀取前100個數字,創建最大值堆。
  • 2.依次讀取餘下的數,與最大值堆做比較,維持最大值堆。
  • 3.將堆進行排序,便可獲得100個有序最大值。

方法二:多路歸併app

  • 1.從大數據中抽取樣本,將須要排序的數據切分爲多個樣本數大體相等的區間,例如:1-100,101-300…
  • 2.將大數據文件切分爲多個小數據文件,這裏要考慮IO次數和硬件資源問題,例如可將小數據文件數設定爲1G(要預留內存給執行時的程序使用)
  • 3.使用最優的算法對小數據文件的數據進行排序,將排序結果按照步驟1劃分的區間進行存儲
  • 4.對各個數據區間內的排序結果文件進行處理,最終每一個區間獲得一個排序結果的文件
  • 5.將各個區間的排序結果合併

注意以上merge時候的方法是循環比較的,假設有n個元素,每一個須要比較k次,複雜度爲O(nk)。更好的辦法使用最小堆實現,具體的方法和下面算法題中合併K個列表同樣。函數

算法題目

合併兩個有序數組

思路:開一個數組存放結果,依次比較兩個list元素的大小,直到一個list爲空,剩下的加入res便可post

def merge(nums1, nums2):
    res = []
    while nums1 and nums2:
            if nums1[0]<nums2[0]:
                res.append(nums1.pop(0))
            else:
                res.append(nums2.pop(0))
                
    res = res+nums1+nums2
    return res

print(merge([1,2,3,4],[3,4,5,6,7]))
複製代碼

合併K個有序數組

注意這種思路很重要學習

能夠利用最小堆完成,時間複雜度是O(nklogk),具體過程以下:測試

  • 建立一個大小爲n*k的數組保存最後的結果
  • 建立一個大小爲k的最小堆,堆中元素爲k個數組中的每一個數組的第一個元素

重複下列步驟n*k次:

  • 每次從堆中取出最小元素(堆頂元素),並將其存入輸出數組中
  • 用堆頂元素所在數組的下一元素將堆頂元素替換掉,
  • 若是數組中元素被取光了,將堆頂元素替換爲無窮大。每次替換堆頂元素後,從新調整堆

初始化最小堆的時間複雜度O(k),總共有kn次循環,每次循環調整最小堆的時間複雜度是O(logk),因此總的時間複雜度是O(knlogk)

合併兩個有序鏈表

思路和合並list同樣

def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        res = ListNode(None)
        node = res
        while l1 and l2:
            if l1.val<l2.val:
                node.next,l1 = l1,l1.next
            else:
                node.next,l2 = l2,l2.next
            node = node.next
        if l1:
            node.next = l1
        else:
            node.next = l2
        return res.next  
複製代碼

合併K個有序鏈表

思路和合並list同樣

def mergeKLists(self, lists):
        """ :type lists: List[ListNode] :rtype: ListNode """

        heap = []
        for ln in lists:
            if ln:
                heap.append((ln.val, ln))
        dummy = ListNode(0)
        cur = dummy
        heapq.heapify(heap)
        while heap:
            valu, ln_index = heapq.heappop(heap)
            cur.next = ln_index
            cur = cur.next
            if ln_index.next:
                heapq.heappush(heap, (ln_index.next.val, ln_index.next))
        return dummy.next
複製代碼

二叉樹的各類遍歷

class Tree:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

def inorder(root):
    stack = []
    result = []
    cur = root
    while stack or cur:
        if cur:
            stack.append(cur)
            cur = cur.left
        else:
            cur = stack.pop()
            result.append(cur.val)
            cur = cur.right
    return result

def preorder(root):  ## 前序遍歷
        stack = []
        result = []
        cur = root
        while stack or cur:
            if cur:
                result.append(cur.val)
                stack.append(cur.right)
                cur = cur.left
            else:
                cur = stack.pop()
        return result

def postorder(root): ## 後序遍歷
        stack = []
        result = []
        cur = root
        while stack or cur:
            if cur:
                result.append(cur.val)
                stack.append(cur.left)
                cur = cur.right
            else:
                cur = stack.pop()
        return result[::-1]

def levelOrder(root): #層次遍歷
    if not root:
        return []
    result = []
    cur = root
    queue = [cur]
    while queue:
        cur = queue.pop(0)
        result.append(cur.val)
        if cur.left:
            queue.append(cur.left)
        if cur.right:
            queue.append(cur.right)
    return result

tree = Tree(1)
tree.left = Tree(2)
tree.left.left = Tree(4)
tree.left.right = Tree(5)
tree.right = Tree(3)
tree.right.left = Tree(6)
tree.right.right = Tree(7)

print(preorder(tree))
print(inorder(tree))
print(postorder(tree))
print(levelOrder(tree))
複製代碼

經常使用算法模板

適用於筆試的時候

二分查找

利用python的庫進行二分查找:bisect_left:數據的左插入區間,bisect_right:數據的右插入區間

from bisect import bisect_left, bisect_right

def find(A, data):
    index = bisect_left(A, data)
    if index != len(A) and A[index] == data :
        return index 
    return None

A = [1,2,2,2,2,3,3,3,3]
index = find(A, 2)
print(index)
複製代碼

有序數組查找某個值的個數

from bisect import bisect_left, bisect_right

def find(A,data):
    return bisect_right(A,data) - bisect_left(A, data)

A = [1,2,2,2,2,3,3,3,3]
res = find(A, data = 2)
print(res)
複製代碼

有序數組區間中元素個數

from bisect import bisect_left, bisect_right

def find(A, min, max):
    return bisect_left(A, min), bisect_right(A, max) 

A = [1,2,2,2,2,3,3,3,3]
l, r = find(A, min = 0.1, max = 2.5)
print(r-l)
複製代碼

迷宮題目的DFS搜索

dirs =[(0 ,1) ,(1 ,0) ,(0 ,-1) ,(-1 ,0)]  # 當前位置四個方向的偏移量
path =[]  # 存找到的路徑

def mark(maze ,pos):  # 給迷宮maze的位置pos標"2"表示「訪問過了」
    maze[pos[0]][pos[1]] =2

def passable(maze ,pos):  # 檢查迷宮maze的位置pos是否可通行
    if pos[0] >=len(maze) or pos[1]>=len(maze[0]) or pos[0] <0 or pos[1] <0 or maze[pos[0]][pos[1]]==1 or maze[pos[0]][pos[1]]==2:
        return False
    return True

def maze_dfs(maze ,start ,end):
    if start==end:
        print(start)
        return
    st= []
    mark(maze ,start)
    st.append(start)  # 入口和方向0的序對入棧
    while st!= [] :  # 走不通時回退
        pos =st.pop()  # 取棧頂及其檢查方向
        for i in range(4):  # 依次檢查未檢查方向,算出下一位置
            nextp = pos[0] + dirs[i][0], pos[1] + dirs[i][1]
            if nextp==end:
                st.append(pos)
                st.append(end)
                print(st)  # 到達出口,打印位置
                return
            if passable(maze , nextp):  # 遇到未探索的新位置
                st.append(pos)  # 原位置和下一方向入棧
                mark(maze ,nextp)
                st.append(nextp)  # 新位置入棧
                break  # 退出內層循環,下次迭代將以新棧頂做爲當前位置繼續
    print("找不到路徑")

if __name__ == '__main__':
    #0表示能夠走通,1表示不能夠走通,2表示走過的位置
    maze = [[0, 1, 0, 0, 1],
            [0, 1, 0, 1, 0],
            [0, 0, 0, 0, 0],
            [0, 1, 1, 1, 0],
            [0, 0, 0, 1, 0]]
    start = (0 ,0)
    end = (4 ,4)
    maze_dfs(maze ,start,end)
複製代碼
相關文章
相關標籤/搜索