資料科學訪談,資料科學家和資料工程師必讀!
> Photo by Francesca Grima on Unsplash
我的Github上提供了完整的Python程式碼。
對於任何與資料相關的採訪,使用Python程式設計都是必不可少的技能,也是必須準備的領域!程式設計問題有四種類型,包括資料結構和演算法,機器學習演算法,數學和統計以及資料操作(請參閱Emma Ding @Airbnb撰寫的精彩文章)。
我在相關文章中闡述了有關資料處理和字串提取的主題。在今天的帖子中,我將重點介紹數學和統計,並對一些大型科技公司(尤其是FAANG)提出的五個Python程式設計問題進行實時編碼。這種型別的問題為您提供了業務設定,並透過模擬請求統計解決方案。
問題1:誰先贏?微軟艾米和布拉德輪流滾動一個漂亮的六邊形模具。誰先擲出" 6"贏得比賽。艾米首先滾動。艾米獲勝的機率是多少?
思路這是一個核心的模擬問題,沒有比模擬大量過程並檢查Amy獲勝的可能性更好的方法了。
艾米滾第一。如果結果為6,則遊戲結束,艾米獲勝。否則,布拉德(Brad)翻牌,如果是6,則贏得比賽。如果不是,則轉回艾米(Amy)。重複該過程,直到有人以6結束遊戲。
在這裡,關鍵是要了解邏輯流程:誰贏了,在什麼情況下贏了。如果艾米得到6分,布拉德必須投擲嗎?沒有。
解題import numpy as npdef who_won(die, size): A_count = 0 # initialize A_count B_count = 0 # initialize B_count for i in range(size): # create an iteration A_6 = np.random.choice(die) # roll the fair dice and choose a random value from 0 to 6 if A_6 == 6: # if A rolls a 6, then A_count adds 1. A_count+=1 # a side-note for Python beginners: the full expression is "A_count = A_count+1." else: # if the above if condition does not fullfill B_6 = np.random.choice(die) # then, it's B's turn to roll the dice, which is a random choice from 0 to 6. if B_6 == 6: # if B rolls a B, B_count adds 1. B_count+=1 return A_count/(A_count+B_count) # return the total number of cases that A won divided by the combined number of A and B wonaka. the result is the probability that Amy wins.
檢查第11行:A_6是Amy的資料分佈,如果她的資料為6,則計數為+1。否則,布拉德可以擲骰子。
在最後(第25行),最終結果應該是Amy獲勝的次數除以Amy和Brad獲勝的總數。一個常見的錯誤是將A_count除以模擬總數。這是不正確的,因為當Amy和Brad都未能擲出6時,會有迭代。
讓我們測試一下上述演算法。
np.random.seed(123)die = [1,2,3,4,5,6]size = 10000who_won(die,size)view raw
0.531271015467384
事實證明,艾米(Amy)在布拉德(Brad)之前就開始滾動贏得這場比賽。艾米(Amy)在10,000次模擬中獲勝的機率為53%。
> Photo by john vicente on Unsplash
問題2:每個主要公司的最大數量為69-給定一個僅由數字6和9組成的正整數num。-返回最多可更改一個數字可得到的最大數字(6變為9,而9變為6)。https://leetcode.com/problems/maximum-69-number/
思路給定一個正整數,只有一種方法可以增大值,即將" 6"變成" 9",而不是相反。另外,我們必須更改最左邊的6;否則,它不是最大數量。例如,我們必須將" 6996"更改為" 9996",而不是" 6999"。
我想出了這個問題的幾種變體:您可以更改一次,也可以全部更改為6。
解決方法1:替換一次# replace oncedef max_69_once(num): return int(str(num).replace('6','9',1))# test casenum = 966666669max_69_once(num)
996666669
在第3行中,我們將整數轉換為字串,然後將第一個" 6"替換為" 9";使用int()將其返回為整數。
解決方案2:全部替換def max_69_all(num): k = len(str(num)) return int(str(num).replace('6','9',k))# test casenum = 966666669max_69_all(num)
999999999
對於第二種情況,我們不必指定k,因為replace()方法預設會更改所有合適的值。我出於教學目的指定了k值。這個問題的另一個變體是替換前兩個或三個" 6"以使數字最大。
> Photo by Alessandro Capuzzi on Unsplash
問題3:有效的完美正方形。Facebook-給定正整數num,編寫一個函式,如果num是一個完美的平方則返回True;否則返回False。-後續操作:請勿使用任何內建庫函式(例如sqrt)。-https://leetcode.com/problems/valid-perfect-square/
思路這非常簡單:檢查正整數是否具有理想的平方根,如果有正整數,則返回True,這可以分兩步完成。
· 找到平方根。
· 檢查它是否是完美的平方根。
棘手的部分是我們必須使用內建庫(例如,數學,Numpy)來計算平方根,這在LeetCode上是一個簡單的問題。如果我們不能使用這些庫,那麼它將成為更具挑戰性和反覆性的問題,這是LeetCode的一箇中等水平的問題。
解決方案1:內建庫import math def valid_perfect_square(num): return int(math.sqrt(num))**2==num # the int() method only returns the integer part and leaves out the decimal part. # For perfect squares, there should be no decimal part. The equation should thus hold.# test case valid_perfect_square(16)
該演算法輕鬆通過了測試案例。應當指出,我們需要使用int()方法僅獲取平方根的整數部分,而忽略任何小數部分。對於完美的正方形,它不會有任何差異,因此等式成立。對於非完美的平方,方程將不成立並返回False。
(特別感謝韓琦發現錯誤!)
解決方案2:沒有內建庫和二進位制搜尋# 1 find the squre root of num# 2 check if it is a perfect square number# solution: no built-in library & binary searchdef valid_perfect_square(num): if num < 2: return True left, right = 2, num//2 # create two pointers: left and right while left<=right: # while loop to constantly update left and right x = left + (right-left)//2# take a wild guess and treat x as the starting point x_squared = x*x # calculate the squared value of x if x_squared == num: # use the following 'if-else' statement to constantly update x_squared. return True # if there are the same, return True if x_squared <num: # if x_squared is smaller than num, left increases by 1 left= x+1 else: # if x_squared is bigger, right decreases by 1 right= x-1 return False # the while loop should continue looping until left and right converge and no common value obtained # test casevalid_perfect_square(16)
如果不允許使用任何庫,則採用二進位制搜尋。LeetCode包含一個詳細的解釋(在此處),我也對此主題發表了另一篇文章(在這裡)。簡而言之,我們建立左右兩個指標,並將這兩個數字的平均值與原始數字進行比較:如果小於該數字,則增加該值;如果更大,我們減少它;或者,如果它們匹配,則返回True。
這些條件將在while迴圈中自動檢查。
#問題4:階乘尾隨零。彭博社-給定整數n,返回n中的尾隨零!
-後續行動:您能否編寫一種適用於對數時間複雜度的解決方案?
-https://leetcode.com/problems/factorial-trailing-zeroes/
思路這個問題有兩個步驟:
· 計算n階乘n!
· 計算尾隨零的數量
對於第一步,我們使用while迴圈迭代遍歷n個階乘並停止迴圈直到1。對於第二步,事情變得有些棘手。
該問題要求尾隨零而不是總數零。這是個很大的差異。8!是40,320,它有2個零,但只有1個尾隨零。我們在計算時必須格外小心。我提出了兩種解決方案。
解決方案1:向後讀取字串# 1 calculate n!# 2 calculate the number of trailing zerosdef factorial_zeros(n): product = n while n > 1 : # iteratively calculate the product product *= (n-1) n-=1 count = 0 for i in str(product)[::-1]: # calculate the number of trailing zeros if i == '0': count+=1 else: break return countfactorial_zeros(20)
計算產品的第一部分是不言而喻的。對於第二部分,我們使用str()方法將乘積轉換為字串,然後向後讀取:如果數字為0,則將count加1;否則為0。否則,我們將打破迴圈。
break命令在這裡至關重要。如前所述,上述函式無需中斷命令即可計算零的總數。
解決方案2:while迴圈def factorial_zeros(n): product = n while n > 1 : # step 1: iteratively calculate the product product *= (n-1) n-=1 count = 0 while product%10 == 0: # step 2: calculate the number of trailing zeros product = product/10 count+=1 return count
第一部分與解決方案1相同,唯一的區別是我們使用while迴圈來計算尾隨數字:對於乘積除以10的乘積,最後一位必須為0。因此,我們使用while迴圈不斷更新while迴圈,直到條件不成立為止。
順便說一句,解決方案2是我最喜歡的計算零的方法。
> Photo by Jamie Fenn on Unsplash
問題5:完美數字,亞馬遜-理想數字是一個正整數,它等於其正因數之和,但不包括數字本身。-整數x的除數是可以將x均勻除的整數。-給定整數n,如果n是完美數則返回true,否則返回false。-https://leetcode.com/problems/perfect-number/
思路這個問題可以分為三個步驟:
· 找出正因數
· 計算總和
· 決定:完美與否
第2步和第3步是不言而喻的,最多不超過一層。但是,棘手的部分是找到正除數。為此,我們可以採用野蠻力方法,並在從1到整數的整個序列中進行迭代。
理論上,它應該適用於一個小整數,但是如果我們執行大數,它將超過時間限制。時間效率不高。
解決方案1:暴力#1. find the positive divisors#2. calculate the sum #3. perfect or not def perfect_number(num): divisors = [] for i in range(1,num): if num%i==0: divisors.append(i) if sum(divisors)==num: return True else: return False # test case 1perfect_number(2)
此方法不適用於較大的值。您的面試官可能會要求更有效的解決方案。
解決方案2:sqrt(n)# solution 2: sqrt(n)def perfect_number(num): if num<=1: return False divisors = set([1]) for i in range(2,int(num**0.5)+1): # from 2 to num**0.5 if num%i==0: divisors.add(i) divisors.add(num//i) return sum(divisors)==num
要找到其除數,我們不必檢查最大為整數的值。例如,要找到100的除數,我們不必檢查從1到100的數字。相反,我們只需要檢查直到100的平方根即10,並且所有其他可用值都已經為包括在內。
這是一種最佳演算法,可為我們節省大量時間。
我的Github上提供了完整的Python程式碼。https://github.com/LeihuaYe/Python_LeetCode_Coding
總結· 在進行了數十次"實踐"編碼之後,最大的收穫就是理解問題並將問題分為多個可操作的元件。
· 在這些可行的部分中,總會有一個步驟使求職者絆倒。諸如"不能使用內建函式/庫"之類的限制。
· 關鍵是逐步編寫自定義函式,並嘗試避免在練習例程中儘可能多地使用內建函式。