Leetcode 刷題pattern - Breadth-First Search - TechBridge 技術 ...

文章推薦指數: 80 %
投票人數:10人

但其實,這題也可以用BFS 解!而且實作非常簡單,舉這個例子是想讓大家看看BFS 也可以應用在沒有明顯graph 結構的問題上,我們會在第四個範例中解釋 ... TechBridge技術共筆部落格 Menu Home About Tags Archives RSS SignIn 前言 身在大CS時代,有越來越多人投入刷題的行列,在眼花撩亂的題海中,要想有效率地刷題,就需要掌握題目解法中,可以在許多地方應用的觀念,才能以簡禦繁。

Huli寫的程式解題新手入門注意事項講得很好,寫題目是為了學會解題的思考方法,確保自己掌握重要的資料結構跟演算法。

這也是為什麼我想要寫這系列的文章,把多個散落在各處的題目銜接起來,以後看到相似的問題就可以舉一反三,而不是去背各題目的解法。

舉例來說,之前遇過一題電話面試,問到的題目是: Input:vectorholidays,intpto holidays表示平日或假日,例如0000011表示前面5天是平日,後面2天是假日。

pto表示最多可以放幾天假。

Output:計算在可以用完pto的情況下,最久可以放多長的假。

範例:holidays={0,0,0,0,0,1,1},pto=2,output=4 因為可以放{0,0,0,1,1,1,1} 基本上因為之前有寫過SlidingWindow的pattern,所以這題很快就寫出來了,也順利進到下一關,所以大家不需要追求把題目都刷完,而是掌握好重要的基礎,接下來就是應用這些基礎就可以面對很多變化題(當然還是會有一些解法很巧妙的題目,但其實大部分公司不會硬出巧妙題)。

放上程式碼給大家參考: #include #include usingnamespacestd; intlongest_holidays(constvector&holidays,intpto){ intlongestHoliday=-1,windowStart=0; for(intwindowEnd=0;windowEndholidays={0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,1}; intlongest_holiday=longest_holidays(holidays,9); cout<queue;//storeallnodeswhicharewaitingtobeprocessed step=0;//numberofstepsneeededfromroottocurrentnode //initialize addroottoqueue; //BFS while(queueisnotempty){ step=step+1; //iteratethenodeswhicharealreadyinthequeue intsize=q.size(); for(inti=0;iqueue;//storeallnodeswhicharewaitingtobeprocessed Setvisited;//storeallthenodesthatwe'vevisited step=0;//numberofstepsneeededfromroottocurrentnode //initialize addroottoqueue; addroottovisited; //BFS while(queueisnotempty){ step=step+1; //iteratethenodeswhicharealreadyinthequeue intsize=queue.size(); for(inti=0;i>&rooms){ //Checkcornercases intm=rooms.size(); if(m<1){return;} intn=rooms[0].size(); if(n<1){return;} //PrepareforBFS intGATE=0,WALL=-1,ROOM=numeric_limits::max(); queue>q; vector>dirs{{0,-1},{-1,0},{0,1},{1,0}}; //Putallgatesintoqueue for(inti=0;i=0;--sz){ paircur=q.front(); q.pop(); if(rooms[cur.first][cur.second]==ROOM){ rooms[cur.first][cur.second]=steps; } if(rooms[cur.first][cur.second]!=WALL){ //Traverseneighbor for(inti=0;i&cur,constint&m,constint&n){ returncur.first>=0&&cur.first=0&&cur.second>&grid){ intm=grid.size(),n=m?grid[0].size():0,islands=0; //走過矩陣的所有element,只要遇到島,就把島都消滅(即'1'->'0') for(inti=0;i>&grid,constint&m,constint&n,constint&i,constint&j){ if(grid[i][j]=='0')return; grid[i][j]='0'; if(i-1>=0){dfs(grid,m,n,i-1,j);} if(i+1=0){dfs(grid,m,n,i,j-1);} if(j+1>&grid){ intm=grid.size(),n=m?grid[0].size():0,islands=0,offsets[]={0,1,0,-1,0}; for(inti=0;i>todo; todo.push({i,j}); while(!todo.empty()){ pairp=todo.front(); todo.pop(); for(intk=0;k<4;k++){ intr=p.first+offsets[k],c=p.second+offsets[k+1]; if(r>=0&&r=0&&c1000,9000,0100,0900,0010,0090,0001,0009->...->...->target 所以就開始有可以使用BFS的影子出現。

換句話說,因為看到有起點、要求最短距離,所以想了"走一步"是什麼意思?然後想到就是把其中一個數字+1或-1。

接著就可以再延伸,發現這就是一個從0000開始,然後假設deadends是已經visit過所以不能再走,的一個BFS問題。

Breadth-FirstSearch解法 classSolution{ public: intopenLock(vector&deadends,stringtarget){ //PrepareforBFS //因為不能走到deadends裡面的排列,所以我們直接放進visited,這樣做BFS時就不會考慮這些路線 unordered_setvisited(deadends.begin(),deadends.end()); arraydigit={'0','1','2','3','4','5','6','7','8','9'}; queuetodo; //假設0000沒有在visited(也就是deadends裡沒有)中,我們才需要開始尋找 if(!visited.count("0000")){ todo.push("0000"); visited.insert("0000"); } //StartBFS intsteps=-1; while(!todo.empty()){ ++steps; for(intsz=todo.size()-1;sz>=0;--sz){ stringcur=todo.front(); todo.pop(); //Checkifit'starget if(cur==target){ returnsteps; } //Gothroughneighbors //如何找到對的neighbor也是這題比較tricky的地方之一 for(inti=0;i<4;++i){ for(intj=-1;j<=1;j+=2){ stringneighbor=cur; //Wraparoundindextopreventout-of-bounderror neighbor[i]=digit[(neighbor[i]-'0'+j+10)%10]; if(!visited.count(neighbor)){ todo.push(neighbor); visited.insert(neighbor); } } } } } return-1; } }; 寫完這題,如果你是BFS新手,應該會覺得頗好玩,因為這題的鄰居找法跟之前有明顯matrix結構的情況不太一樣,而是變成在另一個抽象的搜索空間中做BFS。

Breadth-FirstSearch的第四個範例-Leetcode#279-PerfectSquares 題目 暴力解 暴力法很直覺,反正就每種組合都試試看就對了,例如若要看12至少要由幾個perfectsuqarenumber組成,那就看"1至少要幾個+11至少要幾個"、"2至少要幾個+10至少要幾個"...依此類推,直到比較過所有可能的拆分方法,就知道最少要幾個,實作如下: classSolution{ public: intnumSquares(intn){ if(isPerfectSquare(n)){ return1; } intres=n; for(inti=1;i<=n/2;++i){ intcomb=numSquares(i)+numSquares(n-i); if(combvisited; queuetodo; todo.push(0); visited.insert(0); //StartBFS intsteps=0; while(!todo.empty()){ ++steps; for(intsz=todo.size()-1;sz>=0;--sz){ //Retrievecurrentint intcur=todo.front(); todo.pop(); for(intj=1;jn){break;} else{ if(!visited.count(sum)){ todo.push(sum); visited.insert(sum); } } } } } returnsteps; } }; Breadth-FirstSearch的第五個範例-Leetcode#1284-MinimumNumberofFlipstoConvertBinaryMatrixtoZeroMatrix 題目 這一題是我在某一週的Leetcodecontest寫到的,因為當時我正好寫完上面四個BFS的範例題,對BFS的pattern很有感覺,所以這題很快就寫出來了。

Breadth-FirstSearch解法 因為概念上跟第三個範例有點像,都是在自己想像中的搜索空間中進行BFS,所以這題的想法我就不贅述了,基本上就是把整個matrix的狀態當作node,每翻一次就是走一步,就可以用BFS解決了,附上程式碼: classSolution{ public: intminFlips(vector>&mat){ //Checkcornercases intm=mat.size(); intn=m?mat[0].size():0; if(m<1orn<1){return-1;} //PrepareforBFS set>>visited; queue>>q; q.push(mat); visited.insert(mat); intsteps=0; while(!q.empty()){ for(intsz=q.size()-1;sz>=0;--sz){ vector>cur=q.front(); q.pop(); //已經成功翻成全部都是0 if(allZero(cur)){ returnsteps; } for(intr=0;r>&mat,int&m,int&n,int&r,int&c){ //翻鄰居 if(r-1>=0){mat[r-1][c]=(mat[r-1][c]==1)?0:1;} if(r+1=0){mat[r][c-1]=(mat[r][c-1]==1)?0:1;} if(c+1>&mat){ for(inti=0;i



請為這篇文章評分?