Elements of Programming Interviews in Python The Insiders’ Guide AdnanAziz Tsung-HsienLee AmitPrakash Thisdocumentisasamplingofourbook,ElementsofProgramming Interviews in Python (EPI). Its purpose is to provide examples of EPI’sorganization,content,style,topics,andquality. Thesampler focusessolelyonproblems;inparticular,itdoesnotincludethree chaptersonthenontechnicalaspectsofinterviewing. We’dloveto hearfrom you—we’reespecially interestedinyour suggestionsas to where the exposition can be improved, as well as any insights intointerviewingtrendsyoumayhave. YoucanbuyEPIPythonatAmazon.com(paperback). http://ElementsOfProgrammingInterviews.com AdnanAzizisaResearchScientistatFacebook. Previously,hewasaprofessorattheDepartment ofElectricalandComputerEngineeringatTheUniversityofTexasatAustin,whereheconducted research and taught classes in applied algorithms. He received his Ph.D. from The University of California at Berkeley; his undergraduate degree is from Indian Institutes of Technology Kanpur. He has worked at Google, Qualcomm, IBM, and several software startups. When not designing algorithms,heplayswithhischildren,Laila,Imran,andOmar. Tsung-Hsien Lee is a Senior Software Engineer at Uber. Previously, he worked as a Software Engineer at Google and as Software Engineer Intern at Facebook. He received both his M.S. and undergraduate degrees from National Tsing Hua University. He has a passion for designing and implementingalgorithms. Helikestoapplyalgorithmstoeveryaspectofhislife. Hetakesspecial prideinhelpingtoorganizeGoogleCodeJam2014and2015. AmitPrakashisaco-founderandCTOofThoughtSpot,aSiliconValleystartup. Previously,hewasa MemberoftheTechnicalStaffatGoogle,whereheworkedprimarilyonmachinelearningproblems thatariseinthecontextofonlineadvertising. BeforethatheworkedatMicrosoftinthewebsearch team. HereceivedhisPh.D.fromTheUniversityofTexasatAustin; hisundergraduatedegreeis fromIndianInstitutesofTechnologyKanpur. Whenheisnotimprovingbusinessintelligence,he indulgesinhispassionforpuzzles,movies,travel,andadventureswithNidhiandAanya. ElementsofProgrammingInterviews: TheInsiders’Guide byAdnanAziz,Tsung-HsienLee,andAmitPrakash Copyright©2017AdnanAziz,Tsung-HsienLee,andAmitPrakash. Allrightsreserved. Nopartofthispublicationmaybereproduced,storedinaretrievalsystem,ortransmitted,inany form,orbyanymeans,electronic,mechanical,photocopying,recording,orotherwise,withoutthe priorconsentoftheauthors. The views and opinions expressed in this work are those of the authors and do not necessarily reflecttheofficialpolicyorpositionoftheiremployers. WetypesetthisbookusingLATEXandtheMemoirclass. WeusedTikZtodrawfigures. AllanYtac createdthecover,basedonadesignbriefweprovided. The companion website for the book includes contact information and a list of known errors for eachversionofthebook. Ifyoucomeacrossanerrororanimprovement,pleaseletusknow. Website: http://elementsofprogramminginterviews.com DistributedundertheAttribution-NonCommercial-NoDerivs3.0License Table of Contents I DataStructuresandAlgorithms 1 1 PrimitiveTypes 2 1.1 Computingtheparityofaword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2 Arrays 7 2.1 TheDutchnationalflagproblem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 3 Strings 13 3.1 Interconvertstringsandintegers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.2 Baseconversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 4 LinkedLists 17 4.1 Testforcyclicity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 5 StacksandQueues 21 5.1 ImplementastackwithmaxAPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 5.2 Computebinarytreenodesinorderofincreasingdepth . . . . . . . . . . . . . . . 26 6 BinaryTrees 28 6.1 Testifabinarytreeisheight-balanced . . . . . . . . . . . . . . . . . . . . . . . . . 30 7 Heaps 33 7.1 Mergesortedfiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 8 Searching 37 8.1 Searchasortedarrayforfirstoccurrenceofk . . . . . . . . . . . . . . . . . . . . . 39 9 HashTables 42 9.1 Isananonymousletterconstructible? . . . . . . . . . . . . . . . . . . . . . . . . . 46 10 Sorting 48 10.1 Computetheintersectionoftwosortedarrays . . . . . . . . . . . . . . . . . . . . 50 10.2 Renderacalendar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 11 BinarySearchTrees 54 i 11.1 TestifabinarytreesatisfiestheBSTproperty . . . . . . . . . . . . . . . . . . . . . 56 12 Recursion 59 12.1 Generatethepowerset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 13 DynamicProgramming 63 13.1 Countthenumberofwaystotraversea2Darray . . . . . . . . . . . . . . . . . . . 65 14 GreedyAlgorithmsandInvariants 69 14.1 The3-sumproblem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 15 Graphs 73 15.1 PaintaBooleanmatrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 16 ParallelComputing 78 16.1 ImplementaTimerclass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 II DomainSpecificProblems 81 17 DesignProblems 82 17.1 Designasystemfordetectingcopyrightinfringement . . . . . . . . . . . . . . . . 83 18 LanguageQuestions 85 18.1 Closure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 18.2 Shallowanddeepcopy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 19 Object-OrientedDesign 87 19.1 CreationalPatterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 20 CommonTools 89 20.1 Merginginaversioncontrolsystem . . . . . . . . . . . . . . . . . . . . . . . . . . 89 IIITheHonorsClass 93 21 HonorsClass 94 21.1 Computethegreatestcommondivisor . . . . . . . . . . . . . . . . . . . . . . . 95 21.2 Computethemaximumproductofallentriesbutone . . . . . . . . . . . . . . 96 IV NotationandIndex 99 Notation 100 IndexofTerms 102 Part I Data Structures and Algorithms hapter C 1 Primitive Types Representationistheessenceofprogramming. —“TheMythicalManMonth,” F.P.Brooks,1975 Aprogramupdatesvariablesinmemoryaccordingtoitsinstructions. Variablescomeintypes—a typeisaclassificationofdatathatspellsoutpossiblevaluesforthattypeandtheoperationsthat canbeperformedonit. Atypecanbeprovidedbythelanguageordefinedbytheprogrammer. In Pythoneverythingisanobject—thisincludesBooleans,integers,characters,etc. Primitivetypesbootcamp Writingaprogramtocountthenumberofbitsthataresetto1inanintegerisagoodwaytoget uptospeedwithprimitivetypes. Thefollowingprogramtestsbitsone-at-a-timestartingwiththe least-significantbit. Itillustratesshiftingandmasking;italsoshowshowtoavoidhard-codingthe sizeoftheintegerword. def count_bits(x): num_bits = 0 while x: num_bits += x & 1 x >>= 1 return num_bits SinceweperformO(1)computationperbit,thetimecomplexityisO(n),wherenisthenumberof bitsneededtorepresenttheinteger,e.g.,4bitsareneededtorepresent12,whichis(1100) inbinary. 2 ThetechniquesinSolution1.1onthefacingpage,whichisconcernedwithcountingthenumberof bitsmodulo2,i.e.,theparity,canbeusedtoimprovetheperformanceoftheprogramgivenabove. Knowyourprimitivetypes Python has a number of build-in types: numerics (e.g., integer), sequences (e.g., list), mappings (e.g.,dict),aswellasclasses,instancesandexceptions. Allinstancesofthesetypesareobjects. Integers in Python3 are unbounded—the maximum integer representable is a function of the available memory. The constant sys.maxsize can be used to find the word-size; specifically, it’s the maximum value integer that can be stored in the word, e.g., 2**63 - 1 on a 64-bit machine. Boundsonfloatsarespecifiedinsys.float_info. • Beveryfamiliarwiththebit-wiseoperatorssuchas6&4,1|2,8>>1,-16>>>2,1<<10,˜0,15ˆx. Negative numbers are treated as their 2’s complement value. (There is no concept of an unsignedshiftinPython,sinceintegershaveinfiniteprecision.) 2 Beverycomfortablewiththebitwiseoperators,particularlyXOR. Understandhowtousemasksandcreatetheminanmachineindependentway. Knowfastwaysto clearthelowermostsetbit (andbyextension, setthelowermost0, getits index,etc.) Understandsignednessanditsimplicationstoshifting. Considerusingacachetoaccelerateoperationsbyusingittobrute-forcesmallinputs. Be awarethat commutativity and associativity can beused toperform operations in parallel andreorderoperations. Table1.1:TopTipsforPrimitiveTypes • The key methods for numeric types are abs(-34.5), math.ceil(2.17), math.floor(3.14), min(x,-4), max(3.14, y), pow(2.71, 3.14) (alternately, 2.71 ** 3.14), and math.sqrt(225). • Knowhowtointerconvertintegersandstrings,e.g.,str(42), int(’42’),floatsandstrings, e.g.,str(3.14), float(’3.14’). • Unlike integers, floats are not infinite precision, and it’s convenient to refer to infinity as float(’inf’)andfloat(’-inf’). Thesevaluesarecomparabletointegers,andcanbeused tocreatepsuedomax-intandpseudomin-int. • When comparing floating point values consider using math.isclose()—it is robust, e.g., whencomparingverylargevalues,andcanhandlebothabsoluteandrelativedifferences. • The key methods in random are random.randrange(28), random.randint(8,16), random.random(),random.shuffle(A),andrandom.choice(A). 1.1 Computingtheparityofaword The parity of a binary word is 1 if the number of 1s in the word is odd; otherwise, it is 0. For example, the parity of 1011 is 1, and the parity of 10001000 is 0. Parity checks are used to detect singlebiterrorsindatastorageandcommunication. Itisfairlystraightforwardtowritecodethat computestheparityofasingle64-bitword. Howwouldyoucomputetheparityofaverylargenumberof64-bitwords? Hint:Usealookuptable,butdon’tuse264entries! Solution: Thebrute-forcealgorithmiterativelyteststhevalueofeachbitwhiletrackingthenumber of 1sseen sofar. Since weonly care ifthe numberof 1s iseven orodd, wecan store thenumber modulo2. def parity(x): result = 0 while x: result ^= x & 1 3 x >>= 1 return result ThetimecomplexityisO(n),wherenisthewordsize. Wewillnowdescribeseveralalgorithmsforparitycomputationthataresuperiortothebrute- forcealgorithm. The first improvement is based on erasing the lowest set bit in a word in a single opera- tion, thereby improving performance in the best- and average-cases. Specifically, the expres- sion y = x&~(x − 1), where & is the bitwise-AND operator and ~ is the bitwise complement operator. The variable y is 1 at exactly the lowest bit of x that is 1; all other bits in y are 0. For example, if x = (00101100) , then x − 1 = (00101011) , ~(x − 1) = (11010100) , and 2 2 2 y = (00101100) &(11010100) = (00000100) . Thiscalculationisrobust—itiscorrectforunsigned 2 2 2 andtwo’s-complementrepresentations. Consequently,thisbitmayberemovedfromxbycomput- ingx⊕y,where⊕isthebitwise-XORfunction. ThetimecomplexityisO(s),wheresisthenumber ofbitssetto1inx. def parity(x): result = 0 while x: result ^= 1 x &= x - 1 # Drops the lowest set bit of x. return result Letkbethenumberofbitssetto1inaparticularword. (Forexample,for10001010,k = 3.) Then timecomplexityofthealgorithmaboveisO(k). Thefactthatx&~(x−1)isolatesthelowestbitthatis1inxisimportantenoughthatyoushould memorizeit. However,itisalsofairlyeasytoderive. First,supposexisnot0,i.e.,ithashasabit thatisone. Subtractingonefromxchangestherightmostbittozeroandsetsallthelowerbitsto one(ifyouaddonenow,yougettheoriginalvalueback). Theeffectistomaskouttherightmost one. Thereforex&~(x−1)hasasinglebitsettoone,namely,therightmost1inx. Nowsupposex is0. Subtractingonefromxunderflows,resultinginawordinwhichallbitsaresettoone. Again, x&~(x−1)is0. Asimilarderivationshowsthatx&(x−1)replacesthelowestbitthatis1with0. Forexample, ifx=(00101100) ,thenx−1=(00101011) ,sox&(x−1)=(00101100) &(00101011) =(00101000) . 2 2 2 2 2 Thisfactcanalsobeveryuseful. Wenowconsideraqualitativelydifferentapproach. Theproblemstatementreferstocomputing theparityforaverylargenumberofwords. Whenyouhavetoperformalargenumberofparity computations,and,moregenerally,anykindofbitfiddlingcomputations,twokeystoperformance areprocessingmultiplebitsatatimeandcachingresultsinanarray-basedlookuptable. Firstwedemonstratecaching. Clearly,wecannotcachetheparityofevery64-bitinteger—we would need 264 bits of storage, which is of the order of ten trillion exabytes. However, when computing the parity of a collection of bits, it does not matter how we group those bits, i.e., the computationisassociative. Therefore,wecancomputetheparityofa64-bitintegerbygroupingits bitsintofournonoverlapping16bitsubwords, computingtheparityofeachsubwords, andthen computingtheparity ofthesefour subresults. We choose16since216 = 65536is relativelysmall, 4 whichmakesitfeasibletocachetheparityofall16-bitwordsusinganarray. Furthermore,since16 evenlydivides64,thecodeissimplerthanifwewere,forexample,touse10bitsubwords. We illustrate the approach with a lookup table for 2-bit words. The cache is (cid:104)0,1,1,0(cid:105)—these aretheparitiesof(00),(01),(10),(11), respectively. Tocomputetheparityof(11001010)wewould computetheparitiesof(11),(00),(10),(10). Bytablelookupweseetheseare0,0,1,1,respectively, sothefinalresultistheparityof0,0,1,1whichis0. Tolookuptheparityofthefirsttwobitsin(11101010),werightshiftby6,toget(00000011),and usethisasanindexintothecache. Tolookuptheparityofthenexttwobits,i.e.,(10),werightshift by4,toget(10)inthetwoleast-significantbitplaces. Therightshiftdoesnotremovetheleading (11)—it results in (00001110). We cannot index the cache with this, it leads to an out-of-bounds access. Togetthelasttwobitsaftertherightshiftby4,webitwise-AND(00001110)with(00000011) (this is the “mask” used to extract the last 2 bits). The result is (00000010). Similar masking is neededforthetwoother2-bitlookups. def parity(x): MASK_SIZE = 16 BIT_MASK = 0xFFFF return (PRECOMPUTED_PARITY[x >> (3 * MASK_SIZE)] ^ PRECOMPUTED_PARITY[(x >> (2 * MASK_SIZE)) & BIT_MASK] ^ PRECOMPUTED_PARITY[(x >> MASK_SIZE) & BIT_MASK] ^ PRECOMPUTED_PARITY[x & BIT_MASK]) Thetimecomplexityisafunctionofthesizeofthekeysusedtoindexthelookuptable. LetLbe the width of the words for which we cache the results, and n the word size. Since there are n/L terms, the timecomplexity is O(n/L), assuming word-leveloperations, suchas shifting, take O(1) time. (Thisdoesnotincludethetimeforinitializationofthelookuptable.) WecanimproveontheO(n)worst-casetimecomplexityofthepreviousalgorithmsbyexploiting somesimplepropertiesofparity. Specifically,theXORoftwobitsisdefinedtobe0ifbothbitsare 0 or both bits are 1; otherwise it is 1. XOR has the property of being associative, i.e., it does not matterhowwegroupbits, aswellascommutative, i.e., theorderinwhichweperformtheXORs doesnotchangetheresult. TheXORofagroupofbitsisitsparity. Wecanexploitthisfacttouse theCPU’sword-levelXORinstructiontoprocessmultiplebitsatatime. For example, the parity of (cid:104)b ,b ,...,b ,b ,b ,b (cid:105) equals the parity of the XOR of 63 62 3 2 1 0 (cid:104)b ,b ,...,b (cid:105)and(cid:104)b ,b ,...,b (cid:105). TheXORofthesetwo32-bitvaluescanbecomputedwitha 63 62 32 31 30 0 single shift and a single 32-bit XOR instruction. We repeat the same operation on 32-, 16-, 8-, 4-, 2-,and1-bitoperandstogetthefinalresult. Notethattheleadingbitsarenotmeaningful,andwe havetoexplicitlyextracttheresultfromtheleast-significantbit. Weillustratetheapproachwithan8-bitword. Theparityof(11010111)isthesameastheparity of(1101)XORedwith(0111),i.e.,of(1010). Thisinturnisthesameastheparityof(10)XORedwith (10), i.e., of (00). The final result is the XOR of (0) with (0), i.e., 0. Note that the first XOR yields (11011010),andonlythelast4bitsarerelevantgoingforward. ThesecondXORyields(11101100), andonlythelast2bitsarerelevant. ThethirdXORyields(10011010). Thelastbitistheresult,and toextractitwehavetobitwise-ANDwith(00000001). def parity(x): x ^= x >> 32 x ^= x >> 16 5 x ^= x >> 8 x ^= x >> 4 x ^= x >> 2 x ^= x >> 1 return x & 0x1 ThetimecomplexityisO(logn),wherenisthewordsize. Note that we can combine caching with word-level operations, e.g., by doing a lookup in the XOR-basedapproachoncewegetto16bits. Theactualruntimesdependontheinputdata,e.g.,therefinementofthebrute-forcealgorithm is very fast on sparse inputs. However, for random inputs, the refinement of the brute-force is roughly 20% faster than the brute-force algorithm. The table-based approach is four times faster still,andusingassociativityreducesruntimebyanotherfactoroftwo. Variant:Writeexpressionsthatusebitwiseoperators,equalitychecks,andBooleanoperatorstodo thefollowinginO(1)time. • Rightpropagatetherightmostsetbitinx,e.g.,turns(01010000) to(01011111) . 2 2 • Computexmoduloapoweroftwo,e.g.,returns13for77mod64. • Testifxisapowerof2,i.e.,evaluatestotrueforx=1,2,4,8,...,falseforallothervalues. 6
Description: