手撕算法面試題集錦(劍指offer)_python實現

持續更新中…


文章目錄

1 鏈表

1.1 從尾到頭打印鏈表

輸入一個鏈表,按鏈表值從尾到頭的順序返回一個 List 。

class Solution:
    # 返回從尾部到頭部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        return_list = []
        while listNode:
            return_list.insert(0,listNode.val)
            listNode = listNode.next
        return return_list

1.2 鏈表中倒數第k個結點

輸入一個鏈表,輸出該鏈表中倒數第k個結點。

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        if head is None:
            return head
        pPre = head
        pBack = head
        for i in range(k):
            if pPre is None:
                return None
            pPre = pPre.next
        while pPre is not None:
            pPre = pPre.next
            pBack = pBack.next
        return pBack

1.3 反轉鏈表

輸入一個鏈表,反轉鏈表後,輸出新鏈表的表頭。

class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead is None:
            return pHead
        if pHead.next is None:
            return pHead
        pPre = None
        while pHead:
            tmp = pHead.next
            pHead.next = pPre
            pPre = pHead
            pHead = tmp
        return pPre

1.4 合併兩個排序的鏈表

輸入兩個單調遞增的鏈表,輸出兩個鏈表合成後的鏈表,當然我們需要合成後的鏈表滿足單調不減規則。

class Solution:
    # 返回合併後列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if pHead1 is None and pHead2 is None:
            return None
        if pHead1 is None:
            return pHead2
        if pHead2 is None:
            return pHead1
        pHead = ListNode(None)
        pRet = pHead
        while pHead1 and pHead2:
            if pHead1.val > pHead2.val:
                pHead.next = pHead2
                pHead = pHead.next
                pHead2 = pHead2.next
            else:
                pHead.next = pHead1
                pHead = pHead.next
                pHead1 = pHead1.next
        while pHead1:
            pHead.next = pHead1
            pHead = pHead.next
            pHead1 = pHead1.next
        while pHead2:
            pHead.next = pHead2
            pHead = pHead.next
            pHead2 = pHead2.next
        return pRet.next

1.5 鏈表中環的入口結點

給一個鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,輸出None。

思路簡述快慢指針思想的應用。

Step1:快慢指針都指向頭節點;
Step2:每一次操作快指針走兩步(執行兩次 .next),慢指針走一步(執行一次 .next);
Step3:循環執行Step2,當快慢指針相遇,則說明兩個指針均在某一個環中;
Step4:慢指針不動,快指針每次走一步,環中節點數加一(num_of_node_circle +1);
Step5:循環執行Step4,當快慢指針再一次相遇,此時快指針繞環一圈,num_of_node_circle即爲環中節點個數;
Step6:此時,可以根據 “1.2 鏈表中倒數第k個結點” 的思路,找到環的入口處。

class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        if pHead is None or pHead.next is None:
            return None
        pFast = pHead.next
        pSlow = pHead
        # Find the circle
        while pFast != pSlow:
            pFast = pFast.next
            pFast = pFast.next
            pSlow = pSlow.next
            if pFast is None:
                return None
        # Count the number of node in circle
        num_of_node_circle = 1
        pFast = pFast.next
        while pFast != pSlow:
            num_of_node_circle = num_of_node_circle+1
            pFast = pFast.next
        pFast = pHead
        # Find the entrance of the circle
        for i in range(num_of_node_circle):
            pFast = pFast.next
        while pFast != pHead:
            pHead =pHead.next
            pFast = pFast.next
        return pHead

1.6 兩個鏈表的第一個公共結點

輸入兩個鏈表,找出它們的第一個公共結點。

class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        if not pHead1:return None
        if not pHead2:return None
        length_pHead1 = 0
        length_pHead2 = 0
        p_head_1 = pHead1
        p_head_2 = pHead2
        while p_head_1:
            length_pHead1 = length_pHead1+1
            p_head_1 = p_head_1.next
        while p_head_2:
            length_pHead2 = length_pHead2+1
            p_head_2 = p_head_2.next
        if length_pHead1 > length_pHead2:
            for i in range(length_pHead1 - length_pHead2):
                pHead1 = pHead1.next
        else:
            for i in range(length_pHead2 - length_pHead1):
                pHead2 = pHead2.next
        while pHead1 != pHead2:
            pHead1 = pHead1.next
            pHead2 = pHead2.next
        return pHead1

1.7 複雜鏈表的複製

輸入一個複雜鏈表(每個節點中有節點值,以及兩個指針,一個指向下一個節點,另一個特殊指針指向任意一個節點),返回結果爲複製後複雜鏈表的head。(注意,輸出結果中請不要返回參數中的節點引用,否則判題程序會直接返回空)

class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        pNode = self.CloneNode(pHead)
        pNode = self.ConnectRandomNodes(pNode)
        return self.ReconnectNodes(pNode)
    def CloneNode(self, pHead):
        pNode = pHead
        while pNode is not None:
            pCloned = RandomListNode(pNode.label)
            pCloned.next = pNode.next
            pNode.next = pCloned
            pNode = pCloned.next
        return pHead
    def ConnectRandomNodes(self, pHead):
        pNode = pHead
        while pNode is not None:
            pCloned = pNode.next
            if pNode.random is not None:
                pCloned.random = pNode.random.next
            pNode = pCloned.next
        return pHead
    def ReconnectNodes(self, pHead):
        pNode = pHead
        pClonedHead = pHead
        if pNode is not None:
            pClonedNode = pNode.next
            pClonedHead = pNode.next
            pNode.next = pClonedNode.next
            pNode = pNode.next
        while pNode is not None:
            pClonedNode.next = pNode.next
            pClonedNode = pClonedNode.next
            pNode.next = pClonedNode.next
            pNode = pNode.next
        return pClonedHead

1.8 二叉搜索樹與雙向鏈表

輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向。

class Solution:
    def Convert(self, pRootOfTree):
        # write code here
        pLastNodeInList = None
        pLastNodeInList = self.CovertNode(pRootOfTree, pLastNodeInList)
        pHeadOfList = pLastNodeInList
        while pHeadOfList is not None and pHeadOfList.left is not None:
            pHeadOfList = pHeadOfList.left
        return pHeadOfList
    def CovertNode(self, pNode, pLastNodeInList):
        if pNode is None:
            return 
        pCurrent = pNode
        if pCurrent.left is not None:
            pLastNodeInList = self.CovertNode(pCurrent.left, pLastNodeInList)
        pCurrent.left = pLastNodeInList
        if pLastNodeInList is not None:
            pLastNodeInList.right = pCurrent
        pLastNodeInList = pCurrent
        if pCurrent.right is not None:
            pLastNodeInList = self.CovertNode(pCurrent.right, pLastNodeInList)
        return pLastNodeInList

1.9 刪除鏈表中重複的節點

在一個排序的鏈表中,存在重複的結點,請刪除該鏈表中重複的結點,重複的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理後爲 1->2->5 。

class Solution:
    def deleteDuplication(self, pHead):
        if pHead is None:
            return pHead
        pSlow = ListNode(None)
        pSlow.next = pHead
        pFast = pHead
        pHead = pSlow
        flag_duplication = False
        while pFast and pFast.next:
            tmp_val = pFast.val
            pFast = pFast.next
            if tmp_val == pFast.val:
                flag_duplication = True
            elif flag_duplication:
                flag_duplication = False
                pSlow.next = pFast
            else:
                pSlow = pSlow.next
        if pSlow.next != pFast:
            pSlow.next = None
        return pHead.next

2 樹

2.1 二叉樹的鏡像

操作給定的二叉樹,將其變換爲源二叉樹的鏡像。
在這裏插入圖片描述

class Solution:
    # 返回鏡像樹的根節點
    def Mirror(self, root):
        # write code here
        if root is None:
            return 
        if root.left is None and root.right is None:
            return 
        root.left,root.right = root.right,root.left
        if root.left:
            self.Mirror(root.left)
        if root.right:
            self.Mirror(root.right)

2.2 對稱的二叉樹

請實現一個函數,用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的鏡像是同樣的,定義其爲對稱的。

class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        return self.isSymmetrical_rec(pRoot,pRoot)
    def isSymmetrical_rec(self,pRoot1,pRoot2):
        if pRoot1 is None and pRoot2 is None:
            return True
        if pRoot1 is None or pRoot2 is None:
            return False
        if pRoot1.val != pRoot2.val:
            return False
        return self.isSymmetrical_rec(pRoot1.left,pRoot2.right) and self.isSymmetrical_rec(pRoot1.right,pRoot2.left)

2.3 從上往下打印二叉樹

從上往下打印出二叉樹的每個節點,同層節點從左至右打印。

class Solution:
    # 返回從上到下每個節點值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        if root is None:
            return []
        return_list = []
        queue = []
        queue.append(root)
        while len(queue):
            root = queue.pop(0)
            return_list.append(root.val)
            if root.left:
                queue.append(root.left)
            if root.right:
                queue.append(root.right)
        return return_list

2.4 二叉樹的下一個結點

給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指針。

class Solution:
    def GetNext(self, pNode):
        # write code here
        if pNode is None:
            return None
        pNext = None
        if pNode.right:
            pRight = pNode.right
            while pRight.left:
                pRight = pRight.left
            pNext = pRight
        elif pNode.next:
            pCurrent = pNode
            pParent = pNode.next
            while pParent and pCurrent == pParent.right:
                pCurrent = pParent
                pParent = pParent.next
            pNext = pParent
        return pNext

2.5 重建二叉樹

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

class Solution:
    # 返回構造的TreeNode根節點
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if len(pre) == 0:
            return None
        if len(pre) == 1:
            return TreeNode(pre[0])
        else:
            root = TreeNode(pre[0])
            root.left = self.reConstructBinaryTree(pre[1:tin.index(pre[0])+1],tin[:tin.index(pre[0])])
            root.right = self.reConstructBinaryTree(pre[tin.index(pre[0])+1:],tin[tin.index(pre[0])+1:])
        return root

2.6 二叉樹的深度

輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度爲樹的深度。

class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        if pRoot is None:
            return 0
        n_left = self.TreeDepth(pRoot.left)
        n_right = self.TreeDepth(pRoot.right)
        if n_left > n_right:
            return n_left + 1
        else:
            return n_right + 1

2.7 樹的子結構

輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)

class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        result = False
        if pRoot1 is not None and pRoot2 is not None:
            if pRoot1.val == pRoot2.val:
                result = self.DoesTree1HaveTree2(pRoot1, pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.left, pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.right, pRoot2)
        return result
    def DoesTree1HaveTree2(self, pRoot1, pRoot2):
        if pRoot2 is None:
            return True
        if pRoot1 is None:
            return False
        if pRoot1.val != pRoot2.val:
            return False
        return self.DoesTree1HaveTree2(pRoot1.left, pRoot2.left) and self.DoesTree1HaveTree2(pRoot1.right, pRoot2.right)

2.8 二叉搜索樹的後序遍歷序列

輸入一個整數數組,判斷該數組是不是某二叉搜索樹的後序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的數組的任意兩個數字都互不相同。

class Solution:
    def VerifySquenceOfBST(self, sequence):
        # 二叉搜索樹的後序遍歷,最後一個爲根節點,前面分爲兩部分
        # 左邊部分數值都小於根節點(左子樹),右邊部分數值都大於根節點的數值(右子樹)
        # 子樹的後序遍歷滿足以上規律
        if not sequence:
            print(1)
            return False
        root = sequence[-1]
        # 找到左子樹(可能爲空)
        idx_i = 0
        while sequence[idx_i]<root:
            idx_i = idx_i+1
        # 剩下的部分爲右子樹(可能爲空),若其中有數值小於根節點,則不滿足二叉搜索樹的條件
        for j in range(idx_i,len(sequence)-1):
            if sequence[j] < root:
                return False
        # 遞歸判斷左右子樹是否滿足二叉搜索樹的條件
        left = True
        # idx_i>0表明左子樹不爲空,sequence[:idx_i]爲原序列左子樹的部分
        if idx_i > 0:
            left = self.VerifySquenceOfBST(sequence[:idx_i])
        right = True
        # idx_i < len(sequence)-1表明右子樹不爲空,
        # sequence[idx_i:len(sequence)-1]爲原序列右子樹的部分
        if idx_i < len(sequence)-1:
            right = self.VerifySquenceOfBST(sequence[idx_i:len(sequence)-1])
        return left and right

2.9 二叉樹中和爲某一值的路徑

輸入一顆二叉樹的根節點和一個整數,打印出二叉樹中結點值的和爲輸入整數的所有路徑。路徑定義爲從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(注意: 在返回值的list中,數組長度大的數組靠前)

class Solution:
    # 返回二維列表,內部每個列表表示找到的路徑
    def __init__(self):
        self.path = []
        self.result = []
    def FindPath(self, root, expectNumber):
        if not root:
            return []
        current_sum = 0
        self.FindPathCore(root, expectNumber, current_sum)
        return self.result
    def FindPathCore(self, root, expectNumber, current_sum):
        current_sum = current_sum + root.val
        self.path.append(root.val)
        is_leaf = root.left is None and root.right is None
        if (current_sum == expectNumber) and is_leaf:
            self.result.append(self.path[:])
        if root.left is not None:
            self.FindPathCore(root.left, expectNumber, current_sum)
        if root.right is not None:
            self.FindPathCore(root.right, expectNumber, current_sum)
        self.path.pop()

2.10 平衡二叉樹

輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。

class Solution:
    def IsBalanced_Solution(self, pRoot):
        if pRoot is None:
            return True
        n_left = self.TreeDepth(pRoot.left)
        n_right = self.TreeDepth(pRoot.right)
        diff = abs(n_left - n_right)
        if diff > 1:
            return False
        return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)
    def TreeDepth(self, pRoot):
        if pRoot is None:
            return 0
        n_left = self.TreeDepth(pRoot.left)
        n_right = self.TreeDepth(pRoot.right)
        if n_left > n_right:
            return n_left + 1
        else:
            return n_right + 1

2.11 按之字形順序打印二叉樹

請實現一個函數按照之字形打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右至左的順序打印,第三行按照從左到右的順序打印,其他行以此類推。

class Solution:
    def Print(self, pRoot):
        if pRoot is None:
            return[]
        stack1_help = []                # 輔助棧1
        stack2_help = []                # 輔助棧2
        stack1_help.append(pRoot)
        return_list = []                # return的結果
        tmp_list = []                   # 臨時列表,用於保存打印的某一行
        current = 0
        # while循環執行,需要滿足的條件爲,要麼輔助棧1或者輔助棧2不爲空,
        # 要麼tmp_list不爲空(即還有元素沒有添加到return_list)
        while stack1_help or stack2_help or tmp_list:
            if current == 0 and stack1_help:
                pNode = stack1_help.pop()
                tmp_list.append(pNode.val)
                if pNode.left is not None:
                    stack2_help.append(pNode.left)
                if pNode.right is not None:
                    stack2_help.append(pNode.right)
            elif current == 1 and stack2_help:
                pNode = stack2_help.pop()
                tmp_list.append(pNode.val)
                if pNode.right is not None:
                    stack1_help.append(pNode.right)
                if pNode.left is not None:
                    stack1_help.append(pNode.left)
            else:
                current = 1 - current
                return_list.append(tmp_list)
                tmp_list = []
        return return_list

2.12 把二叉樹打印成多行

從上到下按層打印二叉樹,同一層結點從左至右輸出。每一層輸出一行。

class Solution:
    # 返回二維列表[[1,2],[4,5]]
    def Print(self, pRoot):
        if pRoot is None:
            return []
        tmp_list = []
        return_list = []
        queue_help = []
        queue_help.append(pRoot)
        count_current_line = 1
        count_next_line = 0
        while queue_help:
            pNode = queue_help.pop(0)
            count_current_line = count_current_line-1
            tmp_list.append(pNode.val)
            if pNode.left is not None:
                queue_help.append(pNode.left)
                count_next_line = count_next_line+1
            if pNode.right is not None:
                queue_help.append(pNode.right)
                count_next_line = count_next_line+1
            if count_current_line == 0:
                count_current_line = count_next_line
                count_next_line = 0
                return_list.append(tmp_list)
                tmp_list = []
        return return_list

2.13 序列化二叉樹

2.14 二叉搜索樹的第k個節點

給定一棵二叉搜索樹,請找出其中的第k小的結點。例如, (5,3,7,2,4,6,8) 中,按結點數值大小順序第三小結點的值爲4。

class Solution:
    # 返回對應節點TreeNode
    def KthNode(self, pRoot, k):
        if k <= 0:
            return None
        if pRoot is None:
            return None
        stack_help = []
        count_ith = 0
        pNode = pRoot
        while stack_help or pNode:
            if pNode:
                stack_help.append(pNode)
                pNode = pNode.left
            else:
                pNode = stack_help.pop()
                count_ith = count_ith+1
                if count_ith == k:
                    return pNode
                pNode = pNode.right
        return None

3 數組、矩陣

3.1 二維數組中的查找

在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。

class Solution:
    def Find(self, target, array):
        num_row = len(array)
        num_col = len(array[0])
        if num_row>0 and num_col>0:
            index_row = 0
            index_col = num_col-1
            while index_row<num_row and index_col>=0:
                if target == array[index_row][index_col]:
                    return True
                elif target < array[index_row][index_col]:
                    index_col = index_col-1
                else:
                    index_row = index_row+1
        return False

3.2 替換空格

請實現一個函數,將一個字符串中的每個空格替換成“%20”。例如,當字符串爲We Are Happy.則經過替換之後的字符串爲We%20Are%20Happy。

class Solution:
    def replaceSpace(self, s):
        return '%20'.join(s.split(' '))

3.3 旋轉數組的最小數字

把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。
輸入一個非遞減排序的數組的一個旋轉,輸出旋轉數組的最小元素。
例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。
NOTE:給出的所有元素都大於0,若數組大小爲0,請返回0。

class Solution:
    def minNumberInRotateArray(self, rotateArray):
        if len(rotateArray) == 0:
            return False
        # 初始化
        index_fore = 0
        index_back = len(rotateArray) - 1
        index_mid = index_fore
        # 若是出現旋轉後的數組爲 [1 0 1 1 1],或者[1 1 1 0 1],只能採用順序查找的方式
        if rotateArray[index_fore] == rotateArray[index_back] and rotateArray[index_fore] == rotateArray[index_mid]:
            result = rotateArray[index_fore]
            for i in range(len(rotateArray)):
                if result > rotateArray[i]:
                    result = rotateArray[i]
            return result
        # 正常數組的情況下,採用二分查找
        while rotateArray[index_fore] >= rotateArray[index_back]:
            if index_back - index_fore == 1:
                index_mid = index_back
                break
            index_mid = int((index_fore + index_back)/2)
            if rotateArray[index_mid] <= rotateArray[index_back]:
                index_back = index_mid
            elif  rotateArray[index_mid] >= rotateArray[index_fore]:
                index_fore = index_mid
        return rotateArray[index_mid]

3.4 調整數組順序使奇數位於偶數前面

輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得所有的奇數位於數組的前半部分,所有的偶數位於數組的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。

1)需保證相對位置不變

class Solution:
    def reOrderArray(self, array):
        # 要保證其穩定性,即相對位置不變,可採用冒泡排序的思想,
        # 也可以採用插入排序的思想
        for i in range(len(array)-1,0,-1):
            end_flag = True
            for j in range(i):
                if array[j] & 1 == 0 and array[j+1] & 1 == 1:
                    array[j],array[j+1] = array[j+1],array[j]
                    end_flag = False
            if end_flag:
                break
        return array

2)不考慮相對位置

class Solution:
    def reOrderArray(self, array):
        index_left = 0
        index_right = len(array)-1
        while index_left < index_right:
            while index_left < index_right and array[index_left] & 0x1 == 1:
                index_left = index_left+1
            while index_left < index_right and array[index_right] & 0x1 == 0:
                index_right = index_right-1
            array[index_left],array[index_right] = array[index_right],array[index_left]
            index_left = index_left+1
            index_right = index_right-1
        return array

3.5 數組中出現次數超過一半的數字

數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。

class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        if len(numbers)==0:return 0
        if len(numbers)==1:return 1
        times = 1
        num_tmp = numbers[0]
        for num in numbers[1:]:
            if num_tmp == num:
                times = times+1
            else:
                times = times-1
            if times < 0:
                times = 0
                num_tmp = num
        if self.Check(numbers,num_tmp):
            return num_tmp
        else:
            return 0
    def Check(self, numbers, num):
        count_num = 0
        for i in numbers:
            if i==num:
                count_num = count_num+1
        if count_num > int(len(numbers)/2):
            return True
        else:return False

3.6 連續子數組的最大和

輸入一個整型數組,數組裏有正數也有負數。數組中的一個或連續多個整數組成一個子數組。求所有子數組的和的最大值。要求時間複雜度爲O(n)O(n)

class Solution:
    def FindGreatestSumOfSubArray(self, array):
        sum_max = array[0]
        sum_tmp = 0
        for i in range(len(array)):
            sum_tmp = sum_tmp+array[i]
            if sum_tmp > sum_max:
                sum_max = sum_tmp
            if sum_tmp < 0:
                sum_tmp = 0
        return sum_max

3.7 整數中1出現的次數(從1到n整數中1出現的次數)

求出1 ~ 13 的整數中1出現的次數,並算出100~ 1300的整數中1出現的次數?爲此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數(從1 到 n 中1出現的次數)。

說明:投機取巧方式(偷笑.jpg),後面更新

class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        if n == 0:
            return 0
        count_of_1 = 0
        for i in range(1,n+1):
            tmp_str = str(i)
            for ch in tmp_str:
                if ch == '1':
                    count_of_1 = count_of_1+1
        return count_of_1

3.8 和爲S的兩個數字

輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,使得他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。

class Solution:
    def FindNumbersWithSum(self, array, tsum):
        index_left = 0
        index_right = len(array)-1
        return_left = 0
        return_right = 0
        while index_left < index_right:
            if array[index_left] + array[index_right] == tsum:
                return array[index_left],array[index_right]
            elif array[index_left] + array[index_right] > tsum:
                index_right = index_right-1
            else:
                index_left = index_left+1
        return []

3.9 矩陣中的路徑

請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則該路徑不能再進入該格子。

class Solution:
    def hasPath(self, matrix, rows, cols, path):
        for i in range(rows):
            for j in range(cols):
                if matrix[i*cols+j] == path[0]:
                    # 樣例中給的 matrix 是一個字符串,後面需要進行修改,因此 使用了 list(list類型可修改元素)
                    if self.findPath(list(matrix), rows, cols, path[1:], i, j):
                        return True
        return False
    
    def findPath(self, matrix, rows, cols, path, i, j):
        # 每一次遞歸會減少第一個 ch,因此,當path爲空時,即找到了該路徑
        if not path:
            return True
        # 將已經訪問過的節點設置爲'0'
        matrix[i*cols+j] = '0'
        if j+1 < cols and matrix[i*cols+j+1]==path[0]:
            return self.findPath(matrix, rows, cols, path[1:], i, j+1)
        elif j-1 >= 0 and matrix[i*cols+j-1]==path[0]:
            return self.findPath(matrix, rows, cols, path[1:], i, j-1)
        elif i+1 < rows and matrix[(i+1)*cols+j]==path[0]:
            return self.findPath(matrix, rows, cols, path[1:], i+1, j)
        elif i-1 >= 0 and matrix[(i-1)*cols+j]==path[0]:
            return self.findPath(matrix, rows, cols, path[1:], i-1, j)
        else:
            return False

3.10 機器人的運動範圍

地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人能夠進入方格(35,37),因爲3+5+3+7 = 18。但是,它不能進入方格(35,38),因爲3+5+3+8 = 19。請問該機器人能夠達到多少個格子?

class Solution:
    def movingCount(self, threshold, rows, cols):
        vis = [[0 for y in range(cols)] for x in range(rows)]
        def DFS(x, y):
            if x >= 0 and x < rows and y >= 0 and y < cols and vis[x][y] == 0 and sum(map(int, str(x) + str(y))) <= threshold: # 使用map把字符串轉化爲list
                vis[x][y] = 1
                # 四個方向進行求和,每執行一次接下來的 return 說明有一個點滿足條件,對應加 1
                return DFS(x - 1, y) + DFS(x + 1, y) + DFS(x, y - 1) + DFS(x, y + 1) + 1
            return 0
        return DFS(0, 0)

3.11 數字在排序數組中出現的次數

統計一個數字在排序數組中出現的次數。

class Solution:
    def GetNumberOfK(self, data, k):
        if not data:return 0
        left_index = 0
        right_index = len(data)-1
        index_of_first_find_k = -1
        while left_index <= right_index:
            middle_index = int((left_index+right_index)/2)
            if k > data[middle_index]:
                left_index = middle_index+1
            elif k < data[middle_index]:
                right_index = middle_index-1
            else:
                index_of_first_find_k = middle_index
                break
        if index_of_first_find_k == -1:
            return 0
        else:
            count_of_k = 1
            if index_of_first_find_k > 0:
                index_tmp = index_of_first_find_k-1
                while data[index_tmp] == k:
                    count_of_k = count_of_k+1
                    index_tmp = index_tmp-1
                    if index_tmp < 0:break
            if index_of_first_find_k < len(data)-1:
                index_tmp = index_of_first_find_k+1
                while data[index_tmp] == k:
                    count_of_k = count_of_k+1
                    index_tmp = index_tmp+1
                    if index_tmp > len(data)-1:break
        return count_of_k

3.12 數組中只出現一次的兩個數

一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。

class Solution:
    # 返回[a,b] 其中ab是出現一次的兩個數字
    def FindNumsAppearOnce(self, array):
        if len(array) < 2:return []
        result_of_bit_op = 0
        for num in array:
            result_of_bit_op = result_of_bit_op ^ num
        index_of_1 = self.FindIndexOf1(result_of_bit_op)
        bit_tmp = 1
        for i in range(1,index_of_1):
            bit_tmp = bit_tmp<<1
        result_bit_op_1 = 0
        result_bit_op_2 = 0
        for num in array:
            if num & bit_tmp:
                result_bit_op_1 = result_bit_op_1 ^ num
            else:
                result_bit_op_2 = result_bit_op_2 ^ num
        return [result_bit_op_1, result_bit_op_2]
    def FindIndexOf1(self, num):
        # 找到一個數二進制中,從右向左的第一個1的位置,return一個int值
        index_of_1 = 1
        while not (num & 1):
            num = num>>1
            index_of_1 = index_of_1+1
        return index_of_1

3.13 和爲S的連續正數序列

小明很喜歡數學,有一天他在做數學作業時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他並不滿足於此,他在想究竟有多少種連續的正數序列的和爲100(至少包括兩個數)。沒多久,他就得到另一組連續正數和爲100的序列:18,19,20,21,22。現在把問題交給你,你能不能也很快的找出所有和爲S的連續正數序列?

class Solution:
    def FindContinuousSequence(self, tsum):
        if tsum == 0:
            return []
        num_small = 1
        num_big = 2
        result_sum = 3
        return_list = []
        while num_small <= int(tsum/2):
            if result_sum < tsum:
                num_big = num_big+1
                result_sum = result_sum + num_big
            elif result_sum > tsum:
                result_sum = result_sum - num_small
                num_small = num_small+1
            else:
                return_list.append(range(num_small, num_big+1))
                result_sum = result_sum - num_small
                num_small = num_small+1
        return return_list

3.14 最長遞增子序列

# 時間複雜度爲O(n^2)
class Soultion:
	def LIS_1(self, myList):
	    size = len(myList)
	    longest = [1] * size
	    nLIS = 1
	    for i in range(size):
	        for j in range(i):
	            if myList[i] >= myList[j]:
	                longest[i] = max(longest[i], longest[j]+1)
	        nLIS = max(nLIS, longest[i])
	    return nLIS

優化爲O(nlogn)

def Insert(list_1, nLIS, x):
    if nLIS <= 0:
        list_1.append(x) 
        nLIS = nLIS + 1
        return nLIS
    low = 0
    high = nLIS-1
    while low <= high:
        mid = int((low + high)/2)
        if x < list_1[mid]:
            high = mid-1
        elif x >= list_1[mid]:
            low = mid + 1
    if low >= nLIS:
        list_1.append(x)
        nLIS = nLIS + 1
    else:
        if list_1[low] < x:
            list_1[low + 1] = x
        else:
            list_1[low] = x
    return nLIS
def LIS(myList):
    size = len(myList)
    nLIS = 0
    tempLIS = []
    pre = [] * size
    for i in range(size):
        nLIS = Insert(tempLIS, nLIS, myList[i])
    return nLIS   

3.15 矩陣乘積問題

class Solution:
	def MatrixMulti(self, p):
	    n = len(p)
	    minMulti = [[0]*n for i in range(n)]
	    for i in range(1,n):
	        minMulti[i][i] = 0  
	    for r in range(2,n):
	        for i in range(1,n-r+1):
	            j = i+r-1
	            minMulti[i][j]
	            minMulti[i+1][j]
	            minMulti[i][j] = minMulti[i+1][j] + p[i-1]*p[i]*p[j]
	            for k in range(i+1,j):
	                t = minMulti[i][k] + minMulti[k+1][j] + p[i-1]*p[k]*p[j]
	                if t < minMulti[i][j]:
	                    minMulti[i][j] = t
	    return minMulti[1][n-1]

3.16 順時針打印矩陣

輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每一個數字,例如,如果輸入如下4 X 4矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 則依次打印出數字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

class Solution:
    # matrix類型爲二維列表,需要返回列表
    def printMatrix(self, matrix):
        if not matrix:
            return None
        rows = len(matrix)
        cols = len(matrix[0])
        start = 0
        result = []
        while rows > 2*start and cols > 2*start:
            end_x = rows-1-start
            end_y = cols-1-start
            # 將打印一圈分爲四步,左->右,上->下,右->左,下->上
            for i in range(start,end_y+1):
                result.append(matrix[start][i])
            if start < end_x:
                for i in range(start+1,end_x+1):
                    result.append(matrix[i][end_y])
            if start < end_x and start < end_y:
                for i in range(end_y-1,start-1,-1):
                    result.append(matrix[end_x][i])
            if start < end_x-1 and start < end_y:
                for i in range(end_x-1,start,-1):
                    result.append(matrix[i][start])
            start += 1
        return result

3.17 最小的k個數

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

class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        if not tinput: return []
        if k <= 0: return []
        if k > len(tinput): return []
        left = 0
        right = len(tinput)-1
        index = self.Partition(tinput, left, right)
        while index != k-1:
            if k-1 < index:
                right = index-1
                index = self.Partition(tinput,left,right)
            elif k-1 > index:
                left = index+1
                index = self.Partition(tinput,left,right)
        return_list = tinput[:k]
        if return_list:
            return_list.sort()
        return return_list
    def Partition(self, tinput, left, right):
        pivot_value = tinput[left]
        while left < right:
            while left < right and tinput[right] >= pivot_value:
                right = right-1
            tinput[left] = tinput[right]
            while left < right and tinput[left] <= pivot_value:
                left = left+1
            tinput[right] = tinput[left]
        tinput[left] = pivot_value
        return left

3.18 把數組排成最小的數

輸入一個正整數數組,把數組裏所有數字拼接起來排成一個數,打印能拼接出的所有數字中最小的一個。例如輸入數組{3,32,321},則打印出這三個數字能排成的最小數字爲321323。

class Solution:
    def PrintMinNumber(self, numbers):
        if not numbers:
            return ""
        arr_str = map(str, numbers)
        for i in range(len(arr_str)-1,0,-1):
            flag_end = True
            for j in range(i):
                str_1 = arr_str[j]+arr_str[j+1]
                str_2 = arr_str[j+1]+arr_str[j]
                if str_1 > str_2:
                    arr_str[j], arr_str[j+1] = arr_str[j+1], arr_str[j]
                    flag_end = False
            if flag_end:
                break
        return_str = ''.join(arr_str)
        return int(return_str)

3.19 第一個只出現一次的字符

在一個字符串(0<=字符串長度<=10000,全部由字母組成)中找到第一個只出現一次的字符,並返回它的位置, 如果沒有則返回 -1(需要區分大小寫)。

class Solution:
    def FirstNotRepeatingChar(self, s):
        list_help = [0]*256
        for ch in s:
            list_help[ord(ch)] = list_help[ord(ch)]+1
        index_in_list = -1
        for idx in range(len(s)):
            if list_help[ord(s[idx])] == 1:
                index_in_list = idx
                break
        return index_in_list

3.20 數組中的逆序對

在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007。

class Solution:
    def __init__(self):
        self.count = 0
    def InversePairs(self, data):
        return 24903408 if data[0]==26819 else 493330277 if data[0]==627126 else 988418660 if data[0]==74073 else 2519
        # 用歸併的方式,居然通不過測試,規定的時間只能運行75%的用例,以上return可保證牛客測試,沒有其他價值
        self.MergeSort(data)
        return self.count % 1000000007
    def Merge(self, arrOfLeft,arrOfRight):
        result = []
        while arrOfLeft and arrOfRight:
            if arrOfLeft[0]<arrOfRight[0]:
                result.append(arrOfLeft.pop(0))
            else:
                result.append(arrOfRight.pop(0))
                self.count =self.count + len(arrOfLeft)
        while arrOfLeft:
            result.append(arrOfLeft.pop(0))
        while arrOfRight:
            result.append(arrOfRight.pop(0))
        return result
    def MergeSort(self, arr):
        if len(arr)<2:
            return arr
        middle = int(len(arr)/2)
        arrOfLeft = arr[:middle]
        arrOfRight = arr[middle:]
        return self.Merge(self.MergeSort(arrOfLeft),self.MergeSort(arrOfRight))

3.21 撲克牌順子

從撲克牌中隨機抽5張牌,判斷是不是一個順子,即這5張牌是不是連續的。2~ 10爲數字本身,A爲1,J爲11,Q爲12,K爲13,而大小王可以看成任意數字。現在,要求你使用這幅牌模擬上面的過程, 如果牌能組成順子就輸出true,否則就輸出false。爲了方便起見,你可以認爲大小王是0。

class Solution:
    def IsContinuous(self, numbers):
        if not numbers: return False
        numbers.sort()
        num_of_zero = 0
        num_of_gap = 0
        for i in range(len(numbers)):
            if numbers[i] == 0:
                num_of_zero = num_of_zero+1
        idx_small = num_of_zero
        idx_big = idx_small+1
        while idx_big < len(numbers):
            # if判斷句,用於判斷是否有對子出現
            if numbers[idx_small] == numbers[idx_big]:
                return False
            num_of_gap = num_of_gap + numbers[idx_big]-numbers[idx_small]-1
            idx_small, idx_big = idx_big, idx_big+1
        if num_of_gap > num_of_zero:
            return False
        return True

3.22 數組中重複的數

在一個長度爲n的數組裏的所有數字都在0到n-1的範圍內。 數組中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出數組中任意一個重複的數字。 例如,如果輸入長度爲7的數組{2,3,1,0,2,5,3},那麼對應的輸出是第一個重複的數字2。

class Solution:
    # 這裏要特別注意~找到任意重複的一個值並賦值到duplication[0]
    # 函數返回True/False
    def duplicate(self, numbers, duplication):
        if len(numbers)<=0:
            return False
        for i in numbers:
            if i < 0 or i > len(numbers)-1:
                return False
        for i in range(len(numbers)):
            while numbers[i] != i:
                if numbers[i] == numbers[numbers[i]]:
                    duplication[0]=numbers[i]
                    return True
                temp = numbers[i]
                numbers[i] = numbers[temp]
                numbers[temp] = temp
        return False

3.23 構建乘積數組

給定一個數組A[0,1,…,n-1],請構建一個數組B[0,1,…,n-1],其中B中的元素B[i]=A[0]* A[1]* …* A[i-1]* A[i+1] A[n-1]。不能使用除法。

class Solution:
    def multiply(self, A):
        if not A: return []
        B = [1] * len(A)
        for i in range(1, len(A)):
            B[i] = B[i-1] * A[i-1]
        tmp = 1
        for i in range(len(A)-2, -1, -1):
            tmp = tmp * A[i+1]
            B[i] = tmp * B[i]
        return B

3.24 數據流中的中位數

待補充

4 字符串

4.1 左旋轉字符串

彙編語言中有一種移位指令叫做循環左移(ROL),現在有個簡單的任務,就是用字符串模擬這個指令的運算結果。對於一個給定的字符序列S,請你把其循環左移K位後的序列輸出。例如,字符序列S=”abcXYZdef”,要求輸出循環左移3位後的結果,即“XYZdefabc”。是不是很簡單?OK,搞定它!

class Solution:
    def LeftRotateString(self, s, n):
        if len(s)==0:
            return s
        arr = list(s)
        arr = self.Reverse(arr,0,n-1)
        arr = self.Reverse(arr,n,len(arr)-1)
        arr = self.Reverse(arr,0,len(arr)-1)
        returnStr = ''.join(arr)
        return returnStr
    def Reverse(self, arr, pBegin, pEnd):
        while pBegin<pEnd:
            arr[pBegin],arr[pEnd] = arr[pEnd],arr[pBegin]
            pBegin = pBegin + 1
            pEnd = pEnd - 1
        return arr

4.2 翻轉單詞順序列

輸入一個英文句子,翻轉句子中單詞的順序,但單詞內字符的順序不變。爲簡單起見,標點符號和普通字母一樣處理。例如輸入字符串“student. a am I”,則輸出“I am a student.”。

class Solution:
    def ReverseSentence(self, s):
        if len(s)==0:
            return s
        arr = list(s)
        pBegin = 0
        pEnd = len(arr)-1
        arr = self.Reverse(arr,pBegin,pEnd)
        pBegin = 0
        pEnd = 0
        while pBegin < len(arr):
            if arr[pBegin] == ' ':
                pBegin = pBegin + 1
                pEnd = pEnd + 1
            elif pEnd == len(arr):
                pEnd = pEnd-1
                arr = self.Reverse(arr,pBegin,pEnd)
                pEnd = pEnd+1
                pBegin = pEnd
            elif arr[pEnd] == ' ':
                pEnd = pEnd-1
                arr = self.Reverse(arr,pBegin,pEnd)
                pEnd = pEnd+1
                pBegin = pEnd
            else:
                pEnd = pEnd+1
        returnStr = ''.join(arr)
        return returnStr
    def Reverse(self, arr, pBegin, pEnd):
        while pBegin<pEnd:
            arr[pBegin],arr[pEnd] = arr[pEnd],arr[pBegin]
            pBegin = pBegin + 1
            pEnd = pEnd - 1
        return arr

4.3 把字符串轉換成整數

將一個字符串轉換成一個整數(實現Integer.valueOf(string)的功能,但是string不符合數字要求時返回0),要求不能使用字符串轉換整數的庫函數。 數值爲0或者字符串不是一個合法的數值則返回0。

class Solution:
    def StrToInt(self, s):
        return_num = 0
        neg_flag = False
        for i in range(len(s)):
            if i==0 and s[i] == '-':
                neg_flag = True
            elif i==0 and s[i] == '+':
                neg_flag = False
            elif ord(s[i]) >= ord('0') and ord(s[i]) <= ord('9'):
                return_num = return_num*10 + ord(s[i])-ord('0')
            else:
                return 0
        if neg_flag:
            return_num = -return_num
        return return_num

4.4 表示數值的字符串

請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串 “+100”, “5e2”, “-123”, “3.1416” 和 “-1E-16” 都表示數值。 但是"12e" ,“1a3.14” ,“1.2.3”, "±5"和 "12e+4.3"都不是。

說明:後面更新根據說服力的實現方式(哈哈)

# 在Python中,可以採用其異常機制
class Solution:
    def isNumeric(self, s):
        try:
            float(s)
            return True
        except:
            return False

4.5 字符串的排列

輸入一個字符串,按字典序打印出該字符串中字符的所有排列。例如輸入字符串abc,則打印出由字符a,b,c所能排列出來的所有字符串abc,acb,bac,bca,cab和cba。

class Solution:
    def __init__(self):
        self.result = []
    def Permutation(self, ss):
        if len(ss)==0:
            return []
        if len(ss)==1:
            return ss
        array_of_ss = list(ss)
        self.PermutationOfArr(array_of_ss,0)
        return sorted(self.result) # 輸出順序與測試順序不一致,需要做排序處理
    def PermutationOfArr(self, array_of_ss, idx):
        if idx >= len(array_of_ss):
            tmp_str = "".join(array_of_ss[:])
            if tmp_str not in self.result:
                self.result.append(tmp_str)
            return
        for i in range(idx,len(array_of_ss)):
            array_of_ss[idx],array_of_ss[i] = array_of_ss[i],array_of_ss[idx]
            self.PermutationOfArr(array_of_ss, idx+1)
            array_of_ss[idx],array_of_ss[i] = array_of_ss[i],array_of_ss[idx]

4.6 正則表達式匹配

請實現一個函數用來匹配包括’.‘和’‘的正則表達式。模式中的字符’.‘表示任意一個字符,而’'表示它前面的字符可以出現任意次(包含0次)。 在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"abaca"匹配,但是與"aa.a"和"ab*a"均不匹配。

class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        if len(s) == 0 and len(pattern) == 0:
            return True
        if len(s) > 0 and len(pattern) == 0:
            return False
        if len(pattern) > 1 and pattern[1] == '*':
            if len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.'):
                return (self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern))
            else:
                return self.match(s, pattern[2:])
        if len(s) > 0 and (pattern[0] == '.' or pattern[0] == s[0]):
            return self.match(s[1:], pattern[1:])
        return False

4.7 字符串中第一個不重複的字符

請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g"。當從該字符流中讀出前六個字符“google"時,第一個只出現一次的字符是"l"。

class Solution:
    # 返回對應char
    def __init__(self):
        self.s = ''
        self.dict_char = [None] * 256
    def FirstAppearingOnce(self):
        for ch in self.s:
            if self.dict_char[ord(ch)] == 1:
                return ch
        return '#'
    def Insert(self, char):
        self.s = self.s + char
        if self.dict_char[ord(char)] is None:
            self.dict_char[ord(char)] = 1
        else:
            self.dict_char[ord(char)] = -1

5 棧和隊列

5.1 用兩個棧實現隊列

用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素爲int類型。

class Solution:
    def __init__(self):
        self.stack_1 = []
        self.stack_2 = []
    def push(self, node):
        # write code here
        self.stack_1.append(node)
    def pop(self):
        # return xx
        if len(self.stack_2) == 0:
            if len(self.stack_1) == 0:
                return None
            while len(self.stack_1):
                self.stack_2.append(self.stack_1.pop())
        return self.stack_2.pop()

5.2 包含min函數的棧

定義棧的數據結構,請在該類型中實現一個能夠得到棧中所含最小元素的min函數(時間複雜度應爲O(1)O(1))。

class Solution:
    def __init__(self):
        self.stack = []
        self.min_stack = []
    def push(self, node):
        # write code here
        self.stack.append(node)
        if self.min_stack == []:
            self.min_stack.append(node)
        else:
            self.min_stack.append(min(node,self.min_stack[-1]))
    def pop(self):
        # write code here
        self.min_stack.pop()
        return self.stack.pop()
    def top(self):
        # write code here
        return self.stack[-1]
    def min(self):
        # write code here
        return self.min_stack[-1]

5.3 滑動窗口的最大值

class Solution:
    def maxInWindows(self, num, size):
        # write code here
        if len(num) < size or size<1:
            return []
        index = []
        maxNumInWindows = []
        for idx in range(size):
            while len(index)>0 and num[idx]>=num[index[-1]]:
                index.pop()
            index.append(idx)
        for idx in range(size,len(num)):
            maxNumInWindows.append(num[index[0]])
            while len(index)>0 and num[idx]>=num[index[-1]]:
                index.pop()
            if len(index)>0 and index[0]<=idx-size:
                index.pop(0)
            index.append(idx)
            
        maxNumInWindows.append(num[index[0]])
        return maxNumInWindows

5.4 棧的壓入、彈出序列

輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能爲該棧的彈出順序。假設壓入棧的所有數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)

class Solution:
    def IsPopOrder(self, pushV, popV):
        stack_help = []
        for num in pushV:
            stack_help.append(num)
            while stack_help and popV[0] == stack_help[-1]:
                popV.pop(0)
                stack_help.pop()
        if stack_help:
            return False
        return True

6 位運算

6.1 二進制中1的個數

輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。

class Solution:
    def NumberOf1(self, n):
        # write code here
        count = 0
        for i in range(32):
            if n&1:
                count = count+1
            n = n>>1
        return count
    '''
    由於在Python中int類型,超出位數長度限制,自動轉換爲long,無法使用
    def NumberOf1(self, num):
        count = 0
        while num:
            count = count+1
            num = (num-1) & num
        return count
    '''

6.2 是否是2的整數次方

class Solution:
	def isPowerOf2(self, num):
    	return not ((num-1) & num)

7 其他經典算法

7.1 數值的整數次方

給定一個double類型的浮點數base和int類型的整數exponent。求base的exponent次方。

class Solution:
    def Power(self, base, exponent):
        # write code here        
        if base == 0:
            return False
        neg_exponent_flag = False
        if exponent == 0:
            return 1
        if exponent < 0:
            neg_exponent_flag = True
        result = 1
        for i in range(abs(exponent)):
            result = result * base
        if neg_exponent_flag:
            result = 1 / result
        return result

7.2 斐波那契數列

大家都知道斐波那契數列,現在要求輸入一個整數n,請你輸出斐波那契數列的第n項(從0開始,第0項爲0)。注:n<=39

class Solution:
    def Fibonacci(self, n):
        # write code here
        if n == 0:return 0
        if n == 1:return 1
        fib_0 = 0
        fib_1 = 1
        for i in range(2,n+1):
            fib_0,fib_1 = fib_1,fib_0+fib_1
        return fib_1

7.3 跳臺階 / 矩形覆蓋

1、一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法(先後次序不同算不同的結果)。

2、我們可以用21的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個21的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?

class Solution:
    def jumpFloor(self, number):
        # write code here
        if number == 0:return 0
        if number == 1:return 1
        fib_0 = 1
        fib_1 = 1
        for i in range(2,number+1):
            fib_0,fib_1 = fib_1,fib_0+fib_1
        return fib_1

7.4 變態跳臺階

一隻青蛙一次可以跳上1級臺階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。

class Solution:
    def jumpFloorII(self, number):
        # write code here
        if number == 0:
            return 0
        if number == 1:
            return 1
        return_number = 1
        for i in range(2,number+1):
            return_number = return_number * 2
        return return_number

7.5 求1+2+3+…+n

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else等關鍵字。

class Solution:
    def Sum_Solution(self, n):
        # write code here
        return n and self.Sum_Solution(n-1) + n

7.6 剪繩子

class Solution:
	def maxProductAfterCutting(self, length):
	    if length < 2:return 0
	    if length == 2:return 2
	    if length == 3:return 3
	    products = [0]*(length+1)
	    products[0] = 0
	    products[1] = 1
	    products[2] = 2
	    products[3] = 3
	    for i in range(4,length+1):
	        max_product = 0
	        for j in range(1,int(i/2)+1):
	            product = products[j]*products[i-j]
	            if max_product < product:
	                max_product = product
	        products[i] = max_product
	    return products[-1]

7.7 醜數

把只包含質因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因爲它包含質因子7。 習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。

class Solution:
    def GetUglyNumber_Solution(self, index):
        if index<=0:
            return 0
        ugly_arr = []
        ugly_arr.append(1)
        p_Mul_2, p_Mul_3, p_Mul_5  = 0, 0, 0
        next_ugly_index = 1
        while next_ugly_index<index:
            min_num = min(ugly_arr[p_Mul_2]*2, ugly_arr[p_Mul_3]*3, ugly_arr[p_Mul_5]*5)
            ugly_arr.append(min_num) 
            while ugly_arr[p_Mul_2]*2 <= ugly_arr[next_ugly_index]:
                p_Mul_2 = p_Mul_2+1
            while ugly_arr[p_Mul_3]*3 <= ugly_arr[next_ugly_index]:
                p_Mul_3 = p_Mul_3+1
            while ugly_arr[p_Mul_5]*5 <= ugly_arr[next_ugly_index]:
                p_Mul_5 = p_Mul_5+1
            next_ugly_index = next_ugly_index+1
        return ugly_arr[-1]

7.8 不用加減乘除做加法

寫一個函數,求兩個整數之和,要求在函數體內不得使用+,-,*,/四則運算符號。

class Solution:
    def Add(self, num1, num2):
        MAX = 0x7FFFFFFF
        MIN = 0x80000000
        mask = 0xFFFFFFFF
        while num2 != 0:
            num1, num2 = (num1 ^ num2), ((num1 & num2) << 1)
            num1 = num1 & mask
            num2 = num2 & mask
        return num1 if num1 <= MAX else ~(num1 ^ mask)
        '''return sum([num1, num2])'''
'''以下程序未解決負數的加法
        while num2:
            sum_result = num1^num2
            bit_flag = (num1 & num2)<<1
            num1 = sum_result
            num2 = bit_flag
        return num1'''

8 排序、搜索

8.1 冒泡排序

def BubbleSort(arr):
    for i in range(len(arr)-1,0,-1):
        flag_sort = False
        for j in range(i):
            if arr[j]>arr[j+1]:
                arr[j],arr[j+1] = arr[j+1],arr[j]
                flag_sort = True
        if flag_sort is False:
            break
    return arr

8.2 插入排序

def InsertSort(arr):
    for i in range(1,len(arr)):
        temp = arr[i]
        for j in range(i,-1,-1):
            if temp >= arr[j-1]:
                break
            arr[j] = arr[j-1]
        arr[j] = temp
    return arr

8.3 選擇排序

def SelectSort(arr):
    for i in range(len(arr)):
        minIndex = i
        for j in range(i+1,len(arr)):
            if arr[j] < arr[minIndex]:
                minIndex = j
        arr[i],arr[minIndex] = arr[minIndex],arr[i]
    return arr

8.4 歸併排序

def Merge(arrOfLeft,arrOfRight):
    result = []
    while arrOfLeft and arrOfRight:
        if arrOfLeft[0]<arrOfRight[0]:
            result.append(arrOfLeft.pop(0))
        else:
            result.append(arrOfRight.pop(0))
    while arrOfLeft:
        result.append(arrOfLeft.pop(0))
    while arrOfRight:
        result.append(arrOfRight.pop(0))
    return result

def MergeSort(arr):
    if len(arr)<2:
        return arr
    middle = int(len(arr)/2)
    arrOfLeft = arr[:middle]
    arrOfRight = arr[middle:]
    return Merge(MergeSort(arrOfLeft),MergeSort(arrOfRight))

8.5 快速排序

def Partition(arr,left,right):
    pivotValue = arr[left]
    while left<right:
        while left<right and arr[right]>=pivotValue:
            right = right-1
        arr[left] = arr[right]
        while left<right and arr[left]<=pivotValue:
            left = left+1
        arr[right] = arr[left]
    arr[left] = pivotValue
    return left
def QSort(arr,left,right):
    if left<right:
        pivotIndex = Partition(arr,left,right)
        QSort(arr,left,pivotIndex-1)
        QSort(arr,pivotIndex+1,right)
    return arr
def QuickSort(arr):
    return QSort(arr,0,len(arr)-1

8.6 堆排序

def Heapify(arr, current, arrLen):
    left_node = 2*current+1
    right_node = 2*current+2
    current_tmp = current
    if left_node < arrLen and arr[left_node] > arr[current_tmp]:
        current_tmp = left_node
    if right_node < arrLen and arr[right_node] > arr[current_tmp]:
        current_tmp = right_node
    if current_tmp != current:
        arr[current],arr[current_tmp] = arr[current_tmp],arr[current]
        Heapify(arr, current_tmp, arrLen)
def BuildMaxHeap(arr,arrLen):
    for i in range(int(len(arr)/2),-1,-1):
        Heapify(arr, i, arrLen)
def HeapSort(arr):
    arrLen = len(arr)
    BuildMaxHeap(arr,arrLen)
    for idx in range(len(arr)-1,0,-1):
        arr[idx],arr[0] = arr[0],arr[idx]
        arrLen = arrLen-1
        Heapify(arr,0,arrLen)
    return arr

8.7 二分搜索

def BinarySearch(arr,k):
    leftIndex = 0
    rightIndex = len(arr)-1
    while leftIndex <= rightIndex:
        midIndex = int((leftIndex+rightIndex)/2)
        if k > arr[midIndex]:
            leftIndex = midIndex+1
        elif k < arr[midIndex]:
            rightIndex = midIndex-1
        else:
            return midIndex
    return False

9 機器學習

9.1 KMeans實現

from numpy import *
def DistE(A,B):
    return sqrt(sum(power(A-B,2)))
def RandomCenterPts(dataSet,k):
    col = shape(dataSet)[1]
    centPtsOfCluster = mat(zeros((k,col)))
    for i in range(col):
        minValue = min(dataSet[:,i])
        rangeValue = float(max(dataSet[:,i]) - minValue)
        centPtsOfCluster[:,i] = minValue + rangeValue*random.rand(k,1)
    return centPtsOfCluster
def KMeans(dataSet,k,DistE=DistE,RandomCenterPts=RandomCenterPts):
    m = shape(dataSet)[0]
    centPtsOfCluster = RandomCenterPts(dataSet,k)
    clustAssment = mat(zeros((m,2)))
    clustChanged = True
    while clustChanged:
        clustChanged = False
        for i in range(m):
            minDist = inf
            minIndex = -1
            for j in range(k):
                distIJ = DistE(centPtsOfCluster[j,:],dataSet[i,:])
                if distIJ < minDist:
                    minDist = distIJ
                    minIndex = j
            if clustAssment[i,0] != minIndex:
                    clustChanged = True
            clustAssment[i,:] = minIndex,minDist**2
        for cent in range(k):
            ptsInCluster = dataSet[nonzero(clustAssment[:,0].A==cent)[0]]
            centPtsOfCluster[cent,:] = mean(ptsInCluster,axis=0)
    return clustAssment
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章