Python之10道最高頻的手撕代碼題

目錄

1、快速排序

2、二分查找

3、爬樓梯

4、兩數之和

5、最大回撤

6、合併兩個有序數組

7、最大連續子數組和

8、最長不重複子串

9、全排列

10、三數之和


源於:公衆號Python與算法之美

1、快速排序

題目形式:手寫一下快速排序算法。

題目難度:中等。

出現概率:約50%。手寫快排絕對是手撕代碼面試題中的百獸之王,掌握了它就是送分題,沒有掌握它就是送命題。

參考代碼:

def quick_sort(arr,start=0,end=None):
    if end is None:
        end = len(arr)-1
    if end<=start:
        return(arr)
    i,j = start,end
    ref = arr[start]
    while j>i:
        if arr[j]>= ref:
            j = j - 1
        else:
            # 此處使用一行語句交換3個元素的值
            arr[i],arr[j],arr[i+1] = arr[j],arr[i+1],arr[i]
            i = i + 1
    quick_sort(arr,start=start,end = i-1)
    quick_sort(arr,start=i+1,end = end)
    return(arr)

print(quick_sort([1,1,3,3,2,2,6,6,6,5,5,7]))

輸出結果:

[1, 1, 2, 2, 2, 3, 5, 5, 6, 6, 6, 7]

2、二分查找

題目形式:手寫一下二分查找算法。給定一個有序數組 arr 和一個目標元素 target ,返回該 target 在 arr 中的索引,若不存在,返回-1。

題目難度:簡單。

出現概率:約30%。二分查找絕對是手寫代碼題中的百獸之後,沒有妃子可以和她爭寵。連個二分查找都寫不出來,還來應聘程序員,你是不是對程序員這個職業有什麼誤解?

參考代碼:

def binary_search(arr,target):
    start,end = 0,len(arr)-1
    while True:
        if end - start <=1:
            if target == arr[start]:
                return(start)
            elif target == arr[end]:
                return(end)
            else:
                return(-1)

        mid = (start + end)//2
        if arr[mid]>=target:
            end = mid
        else:
            start = mid

print(binary_search([1,4,7,8,9,12],9))
print(binary_search([1,4,7,8,9,12],3))

輸出結果:

4
-1

3、爬樓梯

題目形式:有一個樓梯,總共有10級臺階,每次只能走一級或者兩級臺階,全部走完,有多少種走法?

題目難度:簡單。

出現概率:約20%。爬樓梯問題是手寫代碼題中的百獸之豹。爬樓梯問題可以用遞歸來解決,但是如果考慮到時間複雜度,最好用動態規劃的思想來處理,這是一個動態規劃算法的教科書級別的案例。連個樓梯都爬不明白,這個算法基礎令人堪憂啊!

參考代碼:

def climb_stairs(n):
    if n==1:
        return 1
    if n==2:
        return 2
    a,b = 1,2
    i = 3
    while i<=n:
        a,b = b,a+b
        i +=1
    return b

print(climb_stairs(10))

輸出結果:

89

4、兩數之和

題目形式:尋找列表中滿足兩數之和等於目標值的元素的下標。例如:arr = [2,7,4,9],target = 6  則返回 [0,2],若不存在,返回空列表[]。

題目難度:簡單。

出現概率:約20%。兩數之和是手寫代碼題中的百獸之狼。兩數之和問題考察候選人對哈希表可以用空間換取時間這個特性的理解。哎呦喂,寫個兩數之和還整上兩重循環了,你這時間複雜度是多少啊?

參考代碼:

def sum_of_two(arr,target):
    dic = {}
    for i,x in enumerate(arr):
        j = dic.get(target-x,-1)
        if j != -1:
            return((j,i))
        else:
            dic[x] = i
    return([])

arr = [2,7,4,9]
target = 6
print(sum_of_two(arr,target))

輸出結果:

(0, 2)

5、最大回撤

題目形式:有一個數組,求其中兩個數x,y,滿足x的索引小於y的索引,使得 x-y 最大。例如 arr = [3,7,2,6,4,1,9,8,5], 最大回撤是6,對應的x=7,y=1。

題目難度:中等。

出現概率:約20%。這道題目可能以買賣股票的最佳時機,或者最大擡升等各種形式出現,這也是一道動態規劃的史詩級範例。呦呵,又整上兩重循環了,這循環寫的很可以啊。

參考代碼:

def max_drawdown(arr):
    assert len(arr)>2, "len(arr) should > 2!"
    x,y = arr[0:2]
    xmax = x
    maxdiff = x-y

    for i in range(2,len(arr)):
        if arr[i-1] > xmax:
            xmax = arr[i-1]
        if xmax - arr[i] > maxdiff:
            maxdiff = xmax - arr[i]
            x,y = xmax,arr[i]

    print("x=",x,",y=",y)
    return(maxdiff)

print(max_drawdown([3,7,2,6,4,1,9,8,5]))

輸出結果:

x= 7 ,y= 1
6

6、合併兩個有序數組

題目形式:給定兩個按升序排列的有序數組,將它們合併成一個新的有序數組。例如:a = [1,2,6,8], b = [2,4,7,10],輸出爲 arr = [1,2,2,4,6,7,8,10]

題目難度:簡單。

出現概率:約15%。這道題目考察的是歸併排序的基本思想。注意,這兩個數組是有序的呢,你怎麼可以無視這麼有利的條件直接拼接上兩個數組開始冒泡了???

參考代碼:

def merge_sorted_array(a,b):
    c = []
    i,j = 0,0
    while True:
        if i==len(a):
            c.extend(b[j:])
            return(c)
        elif j==len(b):
            c.extend(a[i:])
            return(c)
        else:
            if a[i]<b[j]:
                c.append(a[i])
                i=i+1
            else:
                c.append(b[j])
                j=j+1

print(merge_sorted_array([1,2,6,8],[2,4,7,10]))

輸出結果:

[1, 2, 2, 4, 6, 7, 8, 10]

7、最大連續子數組和

題目形式:給定一個數組,求其最大連續子數組的和。例如:arr = [1,5,-10,2,5,-3,2,6,-3,1].  輸出爲:12。對應的連續子數組爲 [2,5,-3,2,6]。

題目難度:中等。

出現概率:約15%。這道題目也是一道動態規劃的祖傳範例。同學,你的這個兩重循環寫的確實很6,但是我們不能認爲你的這道題目做對了!

參考代碼:

def max_sub_array(arr):
    n = len(arr)
    maxi,maxall = arr[0],arr[0]
    for i in range(1,n):
        maxi = max(arr[i],maxi + arr[i])
        maxall = max(maxall,maxi)
    return(maxall)

print(max_sub_array([1,5,-10,2,5,-3,2,6,-3,1]))

輸出結果:

12

8、最長不重複子串

題目形式:給定一個字符串,找出沒有重複字符的最長的子串。例如輸入“abcbefgf”,答案是 “cbefg”。

題目難度:困難。

出現概率:約10%。這是一道動態規劃+哈希查找的綜合應用題。這道題能做出來,你的代碼功底很可以啊。對了,你的期望薪資是多少?

參考代碼:

def longest_substr(s):    
    dic = {}
    start,maxlen,substr = 0,0,""

    for i,x in enumerate(s):
        if x in dic:
            start = max(dic[x]+1,start)
            dic[x] = i   
        else:
            dic[x] = i

        if i-start+1>maxlen:
            maxlen = i-start+1
            substr = s[start:i+1]
    return(substr)

print(longest_substr("abcbefgf"))
print(longest_substr("abcdef"))
print(longest_substr("abbcddefh"))

輸出結果:

cbefg
abcdef
defh

9、全排列

題目形式:給定一個數組,找出其所有可能的排列。例如: arr = [1,1,3],輸出爲 [[1,1,3],[1,3,1],[3,1,1]]。

題目難度:中等

出現概率:約10%。這是一道動態規劃+排列組合的綜合應用題。同學,你這裏用遞歸的話你的這個時間複雜度得有多少?我們這個數組一旦有幾十個元素的話,你這還能跑得動嗎?

參考代碼:

import numpy as np 
def permutations(arr):
    if len(arr)<=1:
        return([arr])
    t = [arr[0:1]]
    i = 1
    while i<=len(arr)-1:
        a = arr[i]
        t = [xs[0:j]+[a]+xs[j:] for xs in t for j in range(i+1)]
        t = np.unique(t,axis=0).tolist()
        i = i+1
    return(t)
print(permutations([1,1,3]))

輸出結果:

[[1, 1, 3], [1, 3, 1], [3, 1, 1]]

 

10、三數之和

題目形式:給定一個數組和目標數target,找出數組中a,b,c滿足 a+b+c = target 的所有組合。例如:arr = [-3,-1,-2,1,2,3],target = 0。輸出爲 [(-3,1,2),(-2,-1,3)]

題目難度:困難

出現概率:約5%。這是一道非常有技巧的題目。你可以嘗試先將arr排序。注意,我們的時間複雜度要求爲O(n**2) ,空間複雜度要求O(1),對,就是這麼嚴格,你要好好想想……喲,有思路啦……emmm……大體上符合要求……同學,你現在手上還有其他家的offer嗎?

參考代碼:

def sum_of_three(arr,target):
    assert len(arr)>=3,"len(arr) should >=3!"
    arr.sort()
    ans = set()
    for k,c in enumerate(arr):
        i,j = k+1,len(arr)-1
        while i<j:
            if arr[i]+arr[j]+c <target:
                i = i+1
            elif arr[i]+arr[j]+c > target:
                j = j-1
            else:
                ans.update({(arr[k],arr[i],arr[j])})
                i = i+1
                j = j-1
    return(list(ans))

print(sum_of_three([-3,-1,-2,1,2,3],0))

輸出結果:

[(-2, -1, 3), (-3, 1, 2)]

 

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