劍指offer(Python版)

目錄

一、線性表

1.數組 

 題3:二維數組中的查找

題14:調整數組順序使得奇數位於偶數前面

題29:數組中出現超過一半的數字

題30:最小的K個數

題33:把數組拍成最小的數

題36:數組中的逆序對 

面試題40:數字在排序數組中出現的次數

題55 數組中重複的數字

面試題52:構建乘積數組

2、鏈(pHead頭節點是實在的,有val!!!!!)

題5:從尾到頭打印鏈表

題15:鏈表中倒數第k個結點

面試題16:反轉鏈表

面試題17:合併兩個排序的鏈表

面試題26:複雜鏈表的複製

面試題37:兩個鏈表的第一個公共結點

面試題56:鏈表中環的入口結點

面試題57:刪除鏈表中重複的結點

面試題4:替換空格

面試題28:字符串的排列

面試題32:從1到n整數中1出現的次數

面試題35:第一個只出現1次的字符

面試題42:反轉單詞順序以及左旋轉字符串反轉單詞順序:

左旋轉字符串:

面試題49:把字符串轉換成整數

面試題53:正則表達式匹配

面試題54:表示數值的字符串

面試題55:字符流中第一個不重複的字符

三、棧和隊列

面試題7:用兩個棧實現隊列&用兩個隊列實現棧

面試題21:包含min函數的棧

面試題22:棧的壓入、彈出序列

面試題65:滑動窗口的最大值

四、樹

面試題6:重建二叉樹

面試題18:樹的子結構

面試題19:二叉樹鏡像

面試題23:從上往下打印二叉樹

面試題24:二叉搜索樹的後序遍歷

面試題25:二叉樹中和爲某一值的路徑

面試題27:二叉搜索樹與雙向鏈表

面試題39:二叉樹的深度

面試題58:二叉樹的下一個節點

面試題59:對稱的二叉樹

面試題60:把二叉樹打印成多行

面試題61:按之字形順序打印二叉樹

面試題62:序列化二叉樹

面試題63:二叉搜索樹的第k個結點

牛客劍指題:平衡二叉樹

五、查找和排序

面試題8:旋轉數組中的最小數字

六、動態規劃

面試題9:斐波那契數列

面試題31:連續子數組的最大和

面試題34:醜數

面試題45:圓圈中最後剩下的數字(約瑟夫環問題)

七、回朔法

面試題66:矩陣中的路徑

面試題67:機器人的運動範圍

八、細節實現題

面試題10:二進制中1的個數

面試題11:數值的整數次方

面試題20:順時針打印矩陣

面試題41:和爲s的兩個數字VS和爲s的連續正數序列

面試題43:n個骰子的點數

面試題44:撲克牌順子

面試題46:求1+2+3+.......+n

面試題47:不用加減乘除做加法

面試題64:數據流中的中位數(樹)


一、線性表

1.數組 

 題3:二維數組中的查找

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

思路:

# -*- coding:utf-8 -*-
class Solution:
    # array 二維列表
    def Find(self, target, array):
        # write code here
        i = 0
        j = len(array[0]) - 1
        while i <= len(array)-1 and j >= 0:
            if array[i][j] > target:
                j = j-1
            elif array[i][j] < target:
                i = i+1
            else:
                return True
        return False

題14:調整數組順序使得奇數位於偶數前面

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

思路:(插入排序)

 i從左到右遍歷,遇到奇數停止,j從i-1向左遍歷,遇偶數交換,j繼續從該位置向左迭代交換偶數。

# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # write code here
        temp = 0
        for i in range(len(array)):
            if array[i]%2 == 1:
                for j in range(i-1,-1,-1):#從i到0逆序
                    if array[j]%2 == 0:#將插入排序法中比大小改爲比奇偶
                        temp = array[j+1]
                        array[j+1] = array[j]
                        array[j] = temp
        return array

題29:數組中出現超過一半的數字

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

思路:

如果有符合條件的數字,則它出現的次數比其他所有數字出現的次數和還要多。在遍歷數組時保存兩個值:一是數組中一個數字,一是次數。遍歷下一個數字時,若它與之前保存的數字相同,則次數加1,否則次數減1;若次數爲0,則保存下一個數字,並將次數置爲1。遍歷結束後,所保存的數字即爲所求。然後再判斷它是否符合條件即可。

# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        if numbers == None:
            return 0
        list_len = len(numbers)
        count = 0
        for i in range(list_len):
            if count == 0:
                result = numbers[i]
            if result == numbers[i]:
                count = count+1
            else:
                count = count -1
        totle_num =  numbers.count(result)
        if totle_num <= list_len/2:#這步很關鍵
            return 0
        return result

題30:最小的K個數

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

思路:size爲k的最大堆,每次拿堆頂和其他數比較,保留較小的。最後對堆序列排序。

# -*- coding:utf-8 -*-
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        n = len(tinput)
        if k <= 0 or k > n:
            return []
        # 建立大頂堆
        for i in range(int(k / 2) - 1, -1, -1):
            self.build_max_head(tinput,k,i)
        for i in range(k, n):
            if tinput[i] < tinput[0]:
                tinput[0], tinput[i] = tinput[i], tinput[0]
                # 調整前k個數
                self.build_max_head(tinput,k,0)
        res = []
        for i in range(k):
            res.append(tinput[i])
        res.sort()
        return res

    def build_max_head(self,arr,heapsize,root_index):
        #根據給定的根節點計算左右節點的index
        left_index = 2*root_index+1
        right_index = left_index+1
        max_num_index = root_index    
        #如果左節點大於根節點,那麼max_num_index=left_index
        if left_index<heapsize and arr[left_index]>arr[max_num_index]:
            max_num_index=left_index    
        #如果右節點大於根節點,那麼max_num_index=right_index
        if right_index<heapsize and arr[right_index]>arr[max_num_index]:
            max_num_index=right_index    
        if  max_num_index != root_index:
            arr[root_index],arr[max_num_index] = arr[max_num_index],arr[root_index]        #進行下一個節點的build_max
            self.build_max_head(arr,heapsize,max_num_index)

題33:把數組拍成最小的數

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

思路:將快排中的比大小改爲兩數拼接的數比大小

# -*- coding:utf-8 -*-
class Solution:
    def quick_sort(self,L,start,end):
        if start < end:
            i,j,mid = start,end,L[start]
            while i<j:
                while i < j and str(L[j])+str(mid) >= str(mid)+str(L[j]):
                    j = j-1
                if i<j :
                    L[i] = L[j]
                while i < j and str(L[i])+str(mid) <= str(mid)+str(L[i]):
                    i = i+1
                if i<j:
                    L[j] = L[i]
            L[i] = mid
            self.quick_sort(L,start,i-1)
            self.quick_sort(L,i+1,end)
        return L
    def PrintMinNumber(self, numbers):
        # write code here
        self.quick_sort(numbers,0,len(numbers)-1)
        res = ''
        for i in range(len(numbers)):
            res = res + str(numbers[i])
        return res

題36:數組中的逆序對 

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

思路:歸併排序,兩組合並的時候,第二組每合併一個數,逆序對就增加第一組剩下的長度。(直接用基礎歸併python會超時)

按歸併排序,把兩個函數合併爲一個,降低時間

# -*- coding:utf-8 -*-
class Solution:
    def InversePairs(self, data):
        # write code here
        return self.merge_sort(data[:], 0, len(data)-1, data[:])%1000000007
    def merge_sort(self, temp, start, end, data):
        if end-start <1:
            return 0
        if end - start == 1:
            if data[start]<=data[end]:
                return 0
            else:
                temp[start], temp[end] = data[end], data[start]
                return 1
        mid = (start+end)//2#(int)((start+end)/2)
        left = self.merge_sort(data,start,mid,temp)
        right = self.merge_sort(data,mid+1,end,temp)
        count = 0
        i = start
        j = mid + 1
        index = start
        while i<=mid and j<=end:
            if data[i] <= data[j]:
                temp[index] = data[i]
                i +=1
            else:
                temp[index] = data[j]
                j+=1
                count += mid-i+1
            index += 1
        while i<=mid:
            temp[index] = data[i]
            i += 1
            index +=1
        while j<=end:
            temp[index] = data[j]
            j += 1
            index += 1
        return count+left+right

面試題40:數字在排序數組中出現的次數

題目描述:統計一個數字在排序數組中出現的次數。

思路:看到有序,用二分查找,找對值爲k的第一個和最後一個座標,相減。

# -*- coding:utf-8 -*-
class Solution:#(0分做法?)
    def GetNumberOfK(self, data, k):
        # write code here
        return data.count(k)

 

# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        left = 0
        right = len(data) - 1
        leftk = self.getleftK(data,k,left,right)
        rightk = self.getrightK(data,k,left,right)
        return rightk-leftk+1
    def getleftK(self,data,k,left,right):
        while left <= right:
            mid = (left+right)//2
            if data[mid]<k:
                left = mid+1
            else:
                right = mid-1
        return left
    def getrightK(self,data,k,left,right):
        while left <= right:
            mid = (left+right)//2
            if data[mid]<=k:
                left = mid+1
            else:
                right = mid-1
        return right

題55 數組中重複的數字

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

思路:(因爲有條件:在一個長度爲n的數組裏的所有數字都在0到n-1的範圍內。)從下標0開始,對每個元素,若numbers[i]不等於i,則交換numbers[i]和numbers[numbers[i]],直至i和numbers[i]相等繼續循環,或numbers[i]和numbers[numbers[i]]相等即遇到重複元素返回True。(注意兩數調換的順序)

# -*- coding:utf-8 -*-
class Solution:
    # 這裏要特別注意~找到任意重複的一個值並賦值到duplication[0]
    # 函數返回True/False
    def duplicate(self, numbers, duplication):
        for i in range(len(numbers)):
            while numbers[i] != i:
                if numbers[i]==numbers[numbers[i]]:
                    duplication[0] = numbers[i]
                    return True
                tmp = numbers[numbers[i]]
                numbers[numbers[i]] = numbers[i]
                numbers[i] = tmp
#                tmp = numbers[i] 
#                numbers[i] = numbers[numbers[i]]
#                numbers[numbers[i]] = tmp#先改變numbers[i]的值會改變numbers[numbers[i]]的位置索引,不行
                #numbers[i],numbers[numbers[i]] = numbers[numbers[i]],numbers[i]
        return False

面試題52:構建乘積數組

題目描述:給定一個數組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]。不能使用除法。

 思路:建立A*A的對角矩陣,對角線爲1 每行相乘即爲B(動態規劃)

# -*- coding:utf-8 -*-
class Solution:
    def multiply(self, A):
        # write code here
        B=[1]*len(A)
        C=[1]*len(A)
        D=[1]*len(A)
        for i in range(1,len(A)):
            C[i]=A[i-1]*C[i-1]
        for j in range(len(A)-2,-1,-1):
            D[j]=A[j+1]*D[j+1]
        for x in range(len(A)):
            B[x]=C[x]*D[x]
        return B

 

2、鏈(pHead頭節點是實在的,有val!!!!!)

題5:從尾到頭打印鏈表

題目描述

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

思路:遍歷鏈表到list,再反轉

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回從尾部到頭部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        res=[]
        node = listNode
        if node == None:
            return []
        if node.next ==None:
            return[listNode.val]
        while node.next !=None:
            res.append(node.val)
            node =node.next
            if node.next ==None:
                res.append(node.val)
        res.reverse()
        return res

題15:鏈表中倒數第k個結點

題目描述:輸入一個鏈表,輸出該鏈表中倒數第k個結點。

思路:設置兩個指針,A指針先走k-1個節點,然後A,B指針一起遍歷,到A結束時讀B所指節點

 

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        a = head
        b = head
        if k==0 or head ==None:
            return None
        if k==1:
            a = b
        if k>1:
            for i in range(k-1):
                a =a.next
                if a==None:
                    return None
        while a.next !=None:
            a =a.next
            b=b.next
        return b

 

面試題16:反轉鏈表

題目描述:輸入一個鏈表,反轉鏈表後,輸出新鏈表的表頭。

思路:直接擼

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead == None or pHead.next ==None:
            return pHead
        temp = pHead.next
        pHead.next = None
        node2 = temp
        node1 = pHead
        while node2 !=None:
            temp = node2.next
            node2.next = node1
            node1 = node2
            node2 = temp
        return node1

面試題17:合併兩個排序的鏈表

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

思路:遞歸

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合併後列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if pHead1 is None:
            return pHead2
        elif pHead2 is None:
            return pHead1
        if pHead1.val < pHead2.val:
            node = pHead1
            node.next = self.Merge(pHead1.next,pHead2)
        else:
            node = pHead2
            node.next = self.Merge(pHead1,pHead2.next)
        return node

面試題26:複雜鏈表的複製

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

思路:先複製每個鏈表結點,並接在每個原結點後面,再將每個random克隆指針賦給克隆節點,最後將原來和克隆節點分開

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        # write code here
        self.clone_nodes(pHead)
        self.connect_random_nodes(pHead)
        return self.divide_list(pHead)
    def clone_nodes(self,pHead):
        node = pHead
        while node is not None:
            clone_node = RandomListNode(node.label)
            clone_node.next = node.next
            node.next = clone_node
            node = clone_node.next
    def connect_random_nodes(self,pHead):
        node = pHead
        while node is not None:
            clone_node = node.next
            if node.random is not None:
                clone_node.random = node.random.next
            node = clone_node.next
    def divide_list(self,pHead):
        node = pHead
        clone_list_head = None
        if node is not None:
            clone_list_head = node.next
            clone_node = node.next
            node.next = clone_node.next
            node = node.next
        while node is not None:
            clone_node.next = node.next
            clone_node = clone_node.next
            node.next = clone_node.next
            node = node.next
        return clone_list_head

面試題37:兩個鏈表的第一個公共結點

題目描述:輸入兩個鏈表,找出它們的第一個公共結點。

思路:暴力遍歷

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        a = []
        x1 = pHead1
        x2 = pHead2
        while x1 is not None:
            a.append(x1.val)
            x1 = x1.next
        while x2 is not None:
            if x2.val in a:
                return x2
            else:
                x2 = x2.next
        return None

思路: 

第一種情況:相同長度有交點
兩個指針一起走,步長一致,碰到第一個相同的節點 p1 == p1,退出循環,return p1。
第二種情況:相同長度無交點
兩個指針一起走,直到走到最後一個節點,p1.next 和 p2.next都爲 None,滿足 相等的條件,退出循環,return p1。
第三種情況:不同長度有交點
兩個指針一起走,當一個指針p1走到終點時,說明p1所在的鏈表比較短,讓p1指向另一個鏈表的頭結點開始走,直到p2走到終點,讓p2指向短的鏈表的頭結點,那麼,接下來兩個指針要走的長度就一樣了,變成第一種情況。
第四種情況:不同長度無交點
兩個指針一起走,當一個指針p1走到終點時,說明p1所在的鏈表比較短,讓p1指向另一個鏈表的頭結點開始走,直到p2走到終點,讓p2指向短的鏈表的頭結點,那麼,接下來兩個指針要走的長度就一樣了,變成第二種情況。

意思是長接短鏈表和短接長鏈表, 如果有公共結點,這倆鏈表後半段相同。

# -*- coding:utf-8 -*-
'''
兩個鏈表的第一個公共節點
題目描述
輸入兩個鏈表,找出它們的第一個公共結點。
'''
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        if not pHead1 or not pHead2:
            return None
        p1, p2 = pHead1, pHead2
        while p1 != p2:
            p1 = pHead2 if not p1 else p1.next
            p2 = pHead1 if not p2 else p2.next
        return p1

面試題56:鏈表中環的入口結點

題目描述:給一個鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,輸出null。

思路:

第一步,找環中相匯點。分別用p1,p2指向鏈表頭部,p1每次走一步,p2每次走二步,直到p1==p2找到在環中的相匯點。

第二步,找環的入口。接上步,當p1==p2時,p2所經過節點數爲2x,p1所經過節點數爲x,設環中有n個節點,p2比p1多走一圈有2x=n+x; n=x;可以看出p1實際走了一個環的步數,再讓p2指向鏈表頭部,p1位置不變,p1,p2每次走一步直到p1==p2; 此時p1指向環的入口。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        if (pHead.next and pHead.next.next) is None:
            return None
        p1 = pHead.next
        p2 = pHead.next.next
        while p1.next and p2.next.next:
            if p1 != p2:
                p1 = p1.next
                p2 = p2.next.next
            else:
                p2 = pHead
                while p1!=p2:
                    p1 = p1.next
                    p2 = p2.next
                return p1
        return None

面試題57:刪除鏈表中重複的結點

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

思路:鏈表前加個新頭節點,刪節點時要保留前面的節點信息

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        first = ListNode(2009)
        last = first
        first.next = pHead
        while first.next and first.next.next:
            if first.next.val == first.next.next.val:
                num = first.next.val
                while first.next and first.next.val == num:
                    first.next = first.next.next
                continue
            first = first.next
        return last.next

面試題4:替換空格

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

# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        s=s.replace(' ','%20')
        return s

面試題28:字符串的排列

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

輸入描述:  輸入一個字符串,長度不超過9(可能有字符重複),字符只包括大小寫字母。
思路:要做字符串的全排列。做法是把對字符串中的每個元素都當做起始位置,把其他元素當做以後的位置,然後再同樣的進行操作。這樣就會得到全排列。

# -*- coding:utf-8 -*-
class Solution:
    def Permutation(self, ss):
        if not ss:
            return []
        res = []
        self.helper(ss, res, '')
        return sorted(list(set(res)))

    def helper(self, ss, res, path):
        if not ss:
            res.append(path)
        else:
            for i in range(len(ss)):
                self.helper(ss[:i] + ss[i+1:], res, path + ss[i])

面試題32:從1到n整數中1出現的次數

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

思路:遍歷各位

1.當前位爲flag十位0,如103,count增加1(high) * 10(flag)

2.當前位爲1,如113,count加1(high)*10 + low(3)+1(cur)

3.當前位爲2-9,如159,count加(1(high)+1)*flag

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        count = 0
        flag = 1
        while n/flag:
            cur = (n/flag)%10
            low = n-(n/flag)*flag
            high = n/(flag*10)
            if cur == 0:
                count += high*flag
            elif cur ==1:
                count += high*flag+low+1
            else:
                count += (high+1)*flag
            flag *=10
        return count

面試題35:第一個只出現1次的字符

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

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        if s =='':
            return -1
        for i in s:
            if s.count(i) == 1:
                return s.index(i)
        return -1

面試題42:反轉單詞順序以及左旋轉字符串
反轉單詞順序:

題目描述:牛客最近來了一個新員工Fish,每天早晨總是會拿着一本英文雜誌,寫些句子在本子上。同事Cat對Fish寫的內容頗感興趣,有一天他向Fish借來翻看,但卻讀不懂它的意思。例如,“student. a am I”。後來才意識到,這傢伙原來把句子單詞的順序翻轉了,正確的句子應該是“I am a student.”。Cat對一一的翻轉這些單詞順序可不在行,你能幫助他麼?

# -*- coding:utf-8 -*-
class Solution:
    def ReverseSentence(self, s):
        # write code here
        a=''
        b=''
        for i in range(len(s)-1,-1,-1):
            if s[i] !=' ':
                a = s[i]+a
            else:
                b = b+a
                b = b+' '
                a = ''
            if i == 0:
                b= b+a
        return b

左旋轉字符串:

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

# -*- coding:utf-8 -*-
class Solution:
    def LeftRotateString(self, s, n):
        # write code here
        return s[n:]+s[0:n]

面試題49:把字符串轉換成整數

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

輸入描述:輸入一個字符串,包括數字字母符號,可以爲空。

輸出描述:如果是合法的數值表達則返回該數字,否則返回0
思路:a放連續字符的整數,b放各段連續整數,若長度爲1則返回。需要判空,判單個‘-’。

 

# -*- coding:utf-8 -*-
class Solution:
    def StrToInt(self, s):
        # write code here
        if s=='':
            return 0
        a=''
        i=0
        b=[]
        while i<len(s):
            if s[i]=='-' or ord(s[i])>=ord('0')and ord(s[i])<=ord('9'):
                a = a+s[i]
            elif a!='':
                b.append(a)
            i +=1
            if i==len(s) and len(a)>0:
                b.append(a)
        if len(b) ==1 and b[0]!='-':
            return int(b[0])
        else:
            return 0

面試題53:正則表達式匹配

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

思路:

特殊:

1、兩個字符串都爲空,返回true

2、當第一個字符串不空,而第二個字符串空了,返回false

而當模式中的第二個字符是“*”時:

如果字符串第一個字符跟模式第一個字符不匹配,則模式後移2個字符,繼續匹配。如果字符串第一個字符跟模式第一個字符匹配,可以有3種匹配方式:

1、模式後移2字符,相當於x*被忽略;

2、字符串後移1字符,模式後移2字符;

3、字符串後移1字符,模式不變,即繼續匹配字符下一位,因爲*可以匹配多位;

當模式中的第二個字符不是“*”時:

1、如果字符串第一個字符和模式中的第一個字符相匹配,那麼字符串和模式都後移一個字符,然後匹配剩餘的。

2、如果 字符串第一個字符和模式中的第一個字符相不匹配,直接返回false。

# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # write code here
        if s=='' and pattern=='':
            return True
        elif s!='' and pattern=='':
            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

面試題54:表示數值的字符串

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

# -*- coding:utf-8 -*-
class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        try:
            float(s)
            return True
        except:
            return False
# -*- coding:utf-8 -*-
class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        e_index = -1
        p_index = -1
        if s.count('.')>1 or (s.count('e')+s.count('E'))>1:
            return False
        for i in range(len(s)):
            if (s[i] =='+' or s[i]=='-') and i>(e_index+1):
                return False
            elif s[i] == 'e'or s[i]=='E':
                e_index = i
            elif s[i] == '.':
                p_index = i
            elif (ord(s[i])<ord('0') or ord(s[i])>ord('9')) and(s[i]!='+'and s[i]!='-'):
                return False
            
            if e_index < p_index and e_index!=-1 or e_index==len(s)-1:
                return False
        return True

面試題55:字符流中第一個不重複的字符

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

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        if s =='':
            return -1
        for i in s:
            if s.count(i) == 1:
                return s.index(i)
        return -1

三、棧和隊列

面試題7:用兩個棧實現隊列&用兩個隊列實現棧

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

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        # write code here
        while len(self.stack2) > 0:
            self.stack1.append(self.stack2.pop())
        self.stack1.append(node)
    def pop(self):
        # return xx
        while len(self.stack1) > 0:
            self.stack2.append(self.stack1.pop())
        return self.stack2.pop()
    #看劍指offer-題7:用兩個棧實現隊列

面試題21:包含min函數的棧

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

思路:建個min的棧,data棧每壓入一個較大的數,min就壓入一個棧頂的數。

# -*- coding:utf-8 -*-
class Solution:
    def __init__:
        self.data_stack = []
        self.min_stack = []
    def push(self, node):
        # write code here
        self.data_stack.append(node)
        if len(self.min_stack) == 0 or node < self.min_stack[-1]:
            self.min_stack.append(node)
        else:
            self.min_stack.append(self.min_stack[-1])
    def pop(self):
        # write code here
        if len(self.data_stack) > 0:
            self.data_stack.pop()
            self.min_stack.pop()
    def top(self):
        # write code here
        return self.data_stack[-1]
    def min(self):
        # write code here
        return self.min_stack[-1]

面試題22:棧的壓入、彈出序列

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

思路:建個空棧,按pushV順序壓入,當棧頂對倒popV的第一個出棧的數時,stack[-1]和popV[0]同時出棧。

# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        stack = []
        while popV:
            if stack and stack[-1] == popV[0]:
                stack.pop()
                popV.pop(0)
            elif pushV:
                stack.append(pushV.pop(0))
            else:
                return False
        return True

面試題65:滑動窗口的最大值

題目描述:給定一個數組和滑動窗口的大小,找出所有滑動窗口裏數值的最大值。例如,如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那麼一共存在6個滑動窗口,他們的最大值分別爲{4,4,6,6,6,5}; 針對數組{2,3,4,2,6,2,5,1}的滑動窗口有以下6個: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
 

# -*- coding:utf-8 -*-
class Solution:
    def maxInWindows(self, num, size):
        # write code here
        if size <= 0:
            return []
        res = []
        for i in range(0, len(num)-size+1):
            res.append(max(num[i:i+size]))
        return res

四、樹

面試題6:重建二叉樹

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回構造的TreeNode根節點
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if len(pre) == 0 :
            return None
        root = TreeNode(pre[0])
        i = tin.index(pre[0])#獲得根節點索引,找出左右子樹
        root.left = self.reConstructBinaryTree(pre[1:i+1],tin[:i])  #序列算頭不算尾
        root.right = self.reConstructBinaryTree(pre[i+1:],tin[i+1:])
        return root
#二叉樹的前序遍歷順序是:先訪問根節點,然後前序遍歷左子樹,再前序遍歷右子樹。
#中序遍歷順序是:中序遍歷根節點的左子樹,然後是訪問根節點,最後中序遍歷右子樹。
#1、二叉樹的前序遍歷序列一定是該樹的根節點
#2、中序遍歷序列中根節點前面一定是該樹的左子樹,後面是該樹的右子樹
#從上面可知,題目中前序遍歷的第一個節點{1}一定是這棵二叉樹的根節點,根據中序遍歷序列,
#可以發現中序遍歷序列中節點{1}之前的{4,7,2}是這棵二叉樹的左子樹,
#{5,3,8,6}是這棵二叉樹的右子樹。然後,對於左子樹,遞歸地把前序子序列{2,4,7}和中序子序列{4,7,2}看成新的前序遍歷和中序遍歷序列。
#此時,對於這兩個序列,該子樹的根節點是{2},該子樹的左子樹爲{4,7}、右子樹爲空,如此遞歸下去(即把當前子樹當做樹,又根據上述步驟分析)。
#{5,3,8,6}這棵右子樹的分析也是這樣。

面試題18:樹的子結構

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        result = False
        if pRoot1 !=None and pRoot2!=None:
            if pRoot1.val == pRoot2.val:
                result = self.isSame(pRoot1,pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.left,pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.right,pRoot2)
        return result
    def isSame(self,pRoot1,pRoot2):
        if pRoot2 ==None:
            return True
        if pRoot1 == None:
            return False
        if pRoot1.val !=pRoot2.val:
            return False
        return self.isSame(pRoot1.left,pRoot2.left) and self.isSame(pRoot1.right,pRoot2.right)

面試題19:二叉樹鏡像

題目描述:操作給定的二叉樹,將其變換爲源二叉樹的鏡像。

思路:遞歸,左右互換

輸入描述:

二叉樹的鏡像定義:源二叉樹 
    	    8
    	   /  \
    	  6   10
    	 / \  / \
    	5  7 9 11
    	鏡像二叉樹
    	    8
    	   /  \
    	  10   6
    	 / \  / \
    	11 9 7  5
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回鏡像樹的根節點
    def Mirror(self, root):
        # write code here
        if root == None:
            return
        elif root.left ==None and root.right == None:
            return
        else:
            temp = root.left
            root.left = root.right
            root.right = temp
            if root.left !=None:
                self.Mirror(root.left)
            if root.right !=None:
                self.Mirror(root.right)

面試題23:從上往下打印二叉樹

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

思路:隊列思想,每一層按順序加入隊列,每次加入節點的左右子樹後將其彈出,最後一個一個彈出。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回從上到下每個節點值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        # write code here
        result = []
        queue = [] #加入了隊列思想
        if root != None:
            queue.append(root) #append 不管什麼類型都可以插入
        while len(queue) != 0:
            tempNode = queue.pop(0)
            result.append(tempNode.val)
            if tempNode.left != None:
                queue.append(tempNode.left)
            if tempNode.right != None:
                queue.append(tempNode.right)
        return result

面試題24:二叉搜索樹的後序遍歷

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

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):#後續遍歷,最後一個爲根節點,大於左子樹,小於右子樹,遞歸
        # write code here
        if not sequence: #在python中 None, False, 空字符串"", 0, 空列表[], 空字典{}, 空元組()都相當於False 
            return False
        root = sequence[-1]
        left = []
        right = []
        i=0
        while sequence[i] < root:
            left.append(sequence[i])
            i += 1     #python不能用i++
        while sequence[i] > root:
            right.append(sequence[i])
            i += 1
        if sequence[i] != root:
            return False
        if len(left) > 0:
            self.VerifySquenceOfBST(left)    #調用自身要加self
        if len(right) > 0:
            self.VerifySquenceOfBST(right)
        return True

面試題25:二叉樹中和爲某一值的路徑

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二維列表,內部每個列表表示找到的路徑
    def FindPath(self, root, expectNumber):
        if not root:
            return []
        tmp = []
        if  not root.left and not root.right and root.val == expectNumber:
            return [[root.val]]
        else:
            left = self.FindPath(root.left,expectNumber-root.val)
            right = self.FindPath(root.right,expectNumber-root.val)
            for item in left+right:
                tmp.append([root.val]+item)
        return tmp

面試題27:二叉搜索樹與雙向鏈表

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

 思路:左子樹上最右結點 -> root -> 右子樹上的最左結點

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.last_node = None
    def Convert(self, pRootOfTree):
        # write code here
        self.convert_node(pRootOfTree)
        head_node = self.last_node
        while head_node is not None and head_node.left is not None:
            head_node = head_node.left
        return head_node
    def convert_node(self, node):
        if node is None:
            return
        cur_node = node
        if cur_node.left is not None:
            self.convert_node(cur_node.left)
        if self.last_node is not None:
            self.last_node.right = cur_node
            cur_node.left = self.last_node
        self.last_node = cur_node
        if cur_node.right is not None:
            self.convert_node(cur_node.right)

面試題39:二叉樹的深度

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.deep = 0
    def TreeDepth(self, pRoot):
        # write code here
        if pRoot:
            n = 1
            self.depth(pRoot,n)
        return self.deep
    def depth(self,pRoot,n):
        if not pRoot.left and not pRoot.right:
            if n>self.deep:
                self.deep = n
        n +=1
        if pRoot.left:
            self.depth(pRoot.left,n)
        if pRoot.right:
            self.depth(pRoot.right,n)
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        if pRoot == None:
            return 0
        if pRoot.left == None and pRoot.right==None:
            return 1
        return max(self.TreeDepth(pRoot.left),self.TreeDepth(pRoot.right))+1

面試題58:二叉樹的下一個節點

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

思路:有以下三種情況: 
a. 如果該結點存在右子結點,那麼該結點的下一個結點是右子結點樹上最左子結點 
b. 如果該結點不存在右子結點,且它是它父結點的左子結點,那麼該結點的下一個結點是它的父結點 
c. 如果該結點既不存在右子結點,且也不是它父結點的左子結點,則需要一路向祖先結點搜索,直到找到一個結點,該結點是其父親結點的左子結點。如果這樣的結點存在,那麼該結點的父親結點就是我們要找的下一個結點。

# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    def GetNext(self, pNode):
        # write code here
        if not pNode:
            return pNode
        if pNode.right:
            p = pNode.right
            while p.left:
                p = p.left
            return p
        p = pNode.next
        while(p and p.right==pNode):#如果不是左節點就返回
            pNode = p
            p = p.next
        return p

面試題59:對稱的二叉樹

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        if not pRoot:
            return True
        return self.same(pRoot.left,pRoot.right)
    def same(self,p,q):
        if not p and not q:
            return True
        if p and q:
            return p.val == q.val and self.same(p.right,q.left)and self.same(p.left,q.right)
        else:
            return False

面試題60:把二叉樹打印成多行

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二維列表[[1,2],[4,5]]
    def Print(self, pRoot):
        # write code here
        if pRoot==None:
            return []
        res = []
        Node = [pRoot]
        while Node:
            temp = []
            temp_N =[]
            for i in Node:
                temp.append(i.val)
                if i.left:
                    temp_N.append(i.left)
                if i.right:
                    temp_N.append(i.right)
            res.append(temp)
            Node = temp_N
        return res

面試題61:按之字形順序打印二叉樹

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

思路:多行打印二叉樹,加個偶數判斷反轉。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        # write code here
        if pRoot==None:
            return []
        res = []
        Node = [pRoot]
        n = 1
        while Node:
            temp = []
            temp_N =[]
            for i in Node:
                temp.append(i.val)
                if i.left:
                    temp_N.append(i.left)
                if i.right:
                    temp_N.append(i.right)
            if n%2==0:
                temp.reverse()
            res.append(temp)
            Node = temp_N
            n +=1
        return res

面試題62:序列化二叉樹

題目描述:請實現兩個函數,分別用來序列化和反序列化二叉樹

思路:將二叉樹轉爲字符串,再從字符串轉爲二叉樹

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Serialize(self, root):
        # write code here
        def doit(node):
            if node:
                vals.append(str(node.val))
                doit(node.left)
                doit(node.right)
            else:
                vals.append('#')
        vals = []
        doit(root)
        return ' '.join(vals)

    def Deserialize(self, s):
        # write code here
        def doit():
            val = next(vals)
            if val == '#':
                return None
            node = TreeNode(int(val))
            node.left = doit()
            node.right = doit()
            return node
        vals = iter(s.split())
        return doit()

面試題63:二叉搜索樹的第k個結點

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

思路:二叉搜索樹的中序遍歷就是有序序列。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回對應節點TreeNode
    def KthNode(self, pRoot, k):
        # write code here
        res = []
        node = pRoot
        while node:
            res.append(node)
            node= node.left
        cnt=0
        while res and cnt<k:
            node = res.pop()
            right = node.right
            while right:
                res.append(right)
                right = right.left
            cnt +=1
        if node and k== cnt:
            return node
        return None

 

牛客劍指題:平衡二叉樹

題目描述:輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。

思考:BST的定義爲|height(lefttree)−height(righttree)|<=1,原問題拆分爲計算樹高度和判斷高度差
 

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def IsBalanced_Solution(self, pRoot):
        # write code here
        if not pRoot:
            return True
        return abs(self.depth(pRoot.left)-self.depth(pRoot.right))<=1
        
    def depth(self,root):
        if not root:
            return 0
        if not root.left and not root.right:
            return 1
        left = self.depth(root.left)
        right = self.depth(root.right)
        return max(left,right)+1

五、查找和排序

面試題8:旋轉數組中的最小數字

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

思想:二分查找(加了)

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if not rotateArray:
            return 0
        left = 0
        right =len(rotateArray)-1
        while left<right:
            mid= (left+right)/2
            if rotateArray[mid]>rotateArray[right]:
                left = mid+1
            else:
                right = mid
        return rotateArray[right]

加了優化相同值的操作。 

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        arr = rotateArray
        if len(arr) ==0:
            return 0
        p1 = 0
        p2 = len(arr) - 1
        mid = p1
        while arr[p1] >= arr[p2]:
            while arr[p1] == arr[p2]:
                p2 -= 1
            if (p2 - p1) == 1:
                return arr[p2]
            mid = (p1+p2)/2
            if arr[mid] > arr[p2]:
                p1 = mid
            else:
                p2 = mid
        return arr[p2]

六、動態規劃

面試題9:斐波那契數列

思想:動態規劃

# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        if n ==0:
            return 0
        if n==1 or n ==2:
            return 1
        dp = [1,1]
        for i in range(n-2):
            dp.append(dp[-1]+dp[-2])
        return dp[-1]

面試題31:連續子數組的最大和

題目描述:HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全爲正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和爲8(從第0個開始,到第3個爲止)。給一個數組,返回它的最大連續子序列的和,你會不會被他忽悠住?(子向量的長度至少是1)

動態規劃求解:(O(n))

# -*- coding:utf-8 -*-
class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        if len(array)==1:
            return array[0]
        dp=array
        for i in range(1,len(array)):
            max_num = max(dp[i-1]+dp[i],dp[i])
            dp[i] = max_num
        return max(dp)

面試題34:醜數

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

思路:設置2,3,5三個計數作爲list索引,加上遞歸,(醜數都是醜數自己相乘)

# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        if (index <= 0):
            return 0
        uglyList = [1]
        indexTwo = 0
        indexThree = 0
        indexFive = 0
        for i in range(index-1):
            newUgly = min(uglyList[indexTwo]*2, uglyList[indexThree]*3, uglyList[indexFive]*5)
            uglyList.append(newUgly)
            if (newUgly % 2 == 0):
                indexTwo += 1
            if (newUgly % 3 == 0):
                indexThree += 1
            if (newUgly % 5 == 0):
                indexFive += 1
        return uglyList[-1]

面試題45:圓圈中最後剩下的數字(約瑟夫環問題)

題目描述:每年六一兒童節,牛客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此。HF作爲牛客的資深元老,自然也準備了一些小遊戲。其中,有個遊戲是這樣的:首先,讓小朋友們圍成一個大圈。然後,他隨機指定一個數m,讓編號爲0的小朋友開始報數。每次喊到m-1的那個小朋友要出列唱首歌,然後可以在禮品箱中任意的挑選禮物,並且不再回到圈中,從他的下一個小朋友開始,繼續0...m-1報數....這樣下去....直到剩下最後一個小朋友,可以不用表演,並且拿到牛客名貴的“名偵探柯南”典藏版(名額有限哦!!^_^)。請你試着想下,哪個小朋友會得到這份禮品呢?(注:小朋友的編號是從0到n-1)

思路:建立0到n-1數組,設立起始點遊標。

# -*- coding:utf-8 -*-
class Solution:
    def LastRemaining_Solution(self, n, m):
        # write code here
        if n <1:
            return -1
        end = -1
        beg = 0
        cnt = [i for i in range(n)]
        while cnt:
            k = (beg+m-1)%n
            end = cnt.pop(k)
            n -=1
            beg = k
        return end

七、回朔法

面試題66:矩陣中的路徑

題目描述:請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則之後不能再次進入這個格子。 例如 a b c e s f c s a d e e 這樣的3 X 4 矩陣中包含一條字符串"bcced"的路徑,但是矩陣中不包含"abcb"路徑,因爲字符串的第一個字符b佔據了矩陣中的第一行第二個格子之後,路徑不能再次進入該格子。
 

# -*- coding:utf-8 -*-
class Solution:
    def hasPath(self, matrix, rows, cols, path):
        if path =='':
            return True
        foot = [True]*rows*cols
        for r in range(rows):
            for c in range(cols):
                if matrix[r*cols+c] == path[0]:
                    foot[r*cols+c] = False
                    if self.dfs(foot,matrix,rows,cols,r,c,path[1:]):
                        return True
                    foot[r*cols+c]=True
        return False
    def dfs(self,foot,matrix,rows,cols,r,c,path):
        if path=='':
            return True
        dx = [-1,1,0,0]
        dy = [0,0,-1,1]
        for k in range(4):
            x = dx[k]+r
            y = dy[k]+c
            if x>=0and x<rows and y>=0 and y<cols and foot[x*cols+y] and matrix[x*cols+y]==path[0]:
                foot[x*cols+y]=False
                if self.dfs(foot,matrix,rows,cols,x,y,path[1:]):
                    return True
                foot[x*cols+y] = True
        return False
# -*- coding:utf-8 -*-
class Solution:
    def hasPath(self, matrix, rows, cols, path):
        assistMatrix = [True]*rows*cols
        for i in range(rows):
            for j in range(cols):
                if(self.hasPathAtAStartPoint(matrix,rows,cols, i, j, path, assistMatrix)):
                    return True
        return False
    def hasPathAtAStartPoint(self, matrix, rows, cols, i, j, path, assistMatrix):
        if not path:
            return True
        index = i*cols+j
        if i<0 or i>=rows or j<0 or j>=cols or matrix[index]!=path[0] or assistMatrix[index]==False:
            return False
        assistMatrix[index] = False
        if(self.hasPathAtAStartPoint(matrix,rows,cols,i+1,j,path[1:],assistMatrix) or
               self.hasPathAtAStartPoint(matrix,rows,cols,i-1,j,path[1:],assistMatrix) or
               self.hasPathAtAStartPoint(matrix,rows,cols,i,j-1,path[1:],assistMatrix) or
               self.hasPathAtAStartPoint(matrix,rows,cols,i,j+1,path[1:],assistMatrix)):
            return True
        assistMatrix[index] = True
        return False

面試題67:機器人的運動範圍

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

# -*- coding:utf-8 -*-
class Solution:
    def movingCount(self, threshold, rows, cols):
        # write code here
        foot = set()
        def dfs(i,j):
            def judge(i,j):
                return sum(map(int,list(str(i))))+sum(map(int,list(str(j))))<=threshold
            if not judge(i,j) or (i,j)in foot:
                return
            foot.add((i,j))
            if i!=rows-1:
                dfs(i+1,j)
            if j!=cols-1:
                dfs(i,j+1)
        dfs(0,0)
        return len(foot)

八、細節實現題

面試題10:二進制中1的個數

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

輸入的是二進制數

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        sum = 0
        for i in range(0,32):#int長32位
            sum += (n>>i & 1)#每一位與1比,>>爲右移
        return sum

面試題11:數值的整數次方

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

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        result = 1.0
        flag = 0
        if base == 0.0:
            return 0
        if base == 1.0 or exponent == 0:
            return 1
        if exponent < 0:
            flag = 1
        for i in range(abs(exponent)):
            result *= base
        if flag == 1:
            result = 1/result
        return result

面試題20:順時針打印矩陣

題目描述:輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每一個數字,例如,如果輸入如下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.

# -*- coding:utf-8 -*-
class Solution:
    # matrix類型爲二維列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        result=[]
        while matrix:
            result=result+matrix.pop(0)
            if not matrix:
                break
            matrix=self.turn(matrix)
        return result
    def turn(self, matrix):
        r=len(matrix)
        c=len(matrix[0])
        B=[]
        for i in range(c):
            A=[]
            for j in range(r):
                A.append(matrix[j][i])
            B.append(A)
        B.reverse()
        return B

面試題41:和爲s的兩個數字VS和爲s的連續正數序列

和爲s的兩個數字:

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

輸出描述:對應每個測試案例,輸出兩個數,小的先輸出。

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        if not array:
            return []
        res = []
        mul = 100000
        left = 0
        right = len(array)-1
        while array[left]*2<tsum:
            while array[right]>tsum-array[left]:
                right -=1
            if mul > array[left]*array[right] and array[right]==tsum-array[left]:
                res =[]
                res.append(array[left])
                res.append(array[right])
                mul = array[left]*array[right]
            left +=1
        return res

面試題43:n個骰子的點數

面試題44:撲克牌順子

題目描述:LL今天心情特別好,因爲他去買了一副撲克牌,發現裏面居然有2個大王,2個小王(一副牌原本是54張^_^)...他隨機從中抽出了5張牌,想測測自己的手氣,看看能不能抽到順子,如果抽到的話,他決定去買體育彩票,嘿嘿!!“紅心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是順子.....LL不高興了,他想了想,決定大\小 王可以看成任何數字,並且A看作1,J爲11,Q爲12,K爲13。上面的5張牌就可以變成“1,2,3,4,5”(大小王分別看作2和4),“So Lucky!”。LL決定去買體育彩票啦。 現在,要求你使用這幅牌模擬上面的過程,然後告訴我們LL的運氣如何, 如果牌能組成順子就輸出true,否則就輸出false。爲了方便起見,你可以認爲大小王是0。
 

# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        if len(numbers)<1:
            return False
        new_nums = [i for i in numbers if i>0]
        max_n = max(numbers)
        min_n = min(new_nums)
        d = []
        if max_n -min_n <5:
            for i in numbers:
                if i != 0 and i in d:
                    return False
                else:
                    d.append(i)
        else:
            return False
        return True

面試題46:求1+2+3+.......+n

題目描述:求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。

 

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

面試題47:不用加減乘除做加法

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

# -*- coding:utf-8 -*-
class Solution:
    def Add(self, num1, num2):
        # write code here
        if not num1:
            return num2
        if not num2:
            return num1
        while num2!=0:
            n1=num1^num2 #異或
            n2=(num1&num2)<<1 #按位與 進位沒有
            num1=n1&0xFFFFFFFF
            num2=n2
        return num1 if num1>>31==0 else num1 - 4294967296

面試題64:數據流中的中位數(樹)

題目描述:如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取數據流,使用GetMedian()方法獲取當前讀取數據的中位數。
 

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.data = []
    def Insert(self, num):
        # write code here
        self.data.append(num)
        self.data.sort()
    def GetMedian(self,data):
        # write code here
        length = len(self.data)
        if length%2 ==1:
            return self.data[length//2]
        else:
            return(self.data[length//2-1]+self.data[length//2])/2.0

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章