今天把百度2016/2017秋招剩餘的4星題目,以及少部分有難度或者比較有趣味的3星題目來一塊兒分析下,因此此次就來個合集了(共包含了4個題目),整體來看題目比較簡單,因此分析也會寫得相對簡略一些。儘管題目比較簡單,可是實際編寫的時候仍是會遇到一些問題,建議本身動手嘗試解答。node
<題目來源: 百度2017秋招 原題連接-可在線提交(賽碼網)>數據結構
有一個nm的格子圖,每一個格子最多與其周圍的四個相鄰,不相鄰的格子之間互相不可達。設一個46的格子圖座標以下:
_ 123456
1 ######
2 ######
3 ######
4 ######
則(2,3)的格子與(1,3),(3,3),(2,2),(2,4)相鄰。
格子與格子之間存在特殊的牆,阻止兩個相鄰的格子的移動。若(2,3)存在一堵左側的牆,則(2,3)將沒法直接到達(2,2),但(2,2)仍能到達(2,3)。
現給出每一個格子周圍牆的狀況,求從給定的點(S,T)出發,到達每個格子最少通過多少個格子。app
這個題目須要求到地鐵每個格子的最短距離,顯然咱們須要從起點不斷地向外擴展,不斷的嘗試移動一步能夠到哪些距離,移動兩步能夠到哪些距距離...如此移動下去直到全部的格子都被到達,咱們能夠確保咱們到達每個格子都是最短的距離。ide
其實這個正是咱們BFS(廣度優先搜索的思想),並且這個題目十分適合做爲BFS的入門題目。咱們首先爲按廣度優先的方式,遍歷這個地圖設置一個方向增量,以便咱們去每次向4個方向擴展(若是沒有圍牆的狀況)spa
dirs = [[-1, 0, 0], [1, 0, 1], [0, -1, 2], [0, 1, 3]]設計
外層列表表示其有4個方向,其中內層列表的含義:
第1位表示要移動到的這個方向,當前x座標須要增長(減小)的單位
第2位寶石要移動到的這個方向,當前y座標須要增長(減小)的單位
第3位表示判斷這個方向是否存在圍牆的二進制位在從低位開始計數的第幾位code
從起點開始擴展,設置一個隊列來存儲到達的那些位置以及距離,每次擴展後的x,y座標和距離都放入這個隊列,而後再從隊列中取出,不斷進行擴展,要主要判斷邊界和圍牆的狀況。orm
讓然,這個題目也能夠按最短路徑的方式,上下左右相鄰的兩個點只要沒有圍牆,就建一條邊,而後從起點求一次單源點最短路徑便可。xml
const_x = 0 const_y = 1 const_wall_bit = 2 dirs = [[-1, 0, 0], [1, 0, 1], [0, -1, 2], [0, 1, 3]] def bfs(map_info, dist, n, m, s, t): que = [(s, t)] dist[s][t] = 0 while len(que): cur_x, cur_y = que.pop(0) for d in dirs: if 1 <= cur_x + d[const_x] <= n and 1 <= cur_y + d[const_y] <= m and \ not map_info[cur_x][cur_y] & (1 << d[const_wall_bit]) and \ dist[cur_x + d[const_x]][cur_y + d[const_y]] == -1: dist[cur_x + d[const_x]][cur_y + d[const_y]] = dist[cur_x][cur_y] + 1 que.append((cur_x + d[const_x], cur_y + d[const_y])) def main(): t_cases = int(raw_input()) for t_case in range(1, t_cases + 1): temp = raw_input().split(' ') n, m, s, t = int(temp[0]), int(temp[1]), int(temp[2]), int(temp[3]) map_info = [[0 for i in range(m + 2)] for i in range(n + 2)] for i in range(1, n + 1): line = raw_input().split(' ') for j in range(1, m + 1): map_info[i][j] = int(line[j - 1]) dist = [[-1 for i in range(m + 2)] for i in range(n + 2)] bfs(map_info, dist, n, m, s, t) print 'Case {}:'.format(t_case) for i in range(1, n + 1): for j in range(1, m + 1): print dist[i][j], print if __name__ == '__main__': main()
<題目來源:百度2017秋招 原題連接-可在線提交(賽碼網)>隊列
可擴展標記語言(英語:Extensible Markup Language,簡稱:XML),是一種標記語言。
XML 設計用來傳送及攜帶數據信息,不用來表現或展現數據,HTML語言則用來表現數據,因此 XML 用途的焦點是它說明數據是什麼,以及攜帶數據信息。
例如,下面是一段 XML 標籤。
<recipe> <recipename>Ice Cream Sundae</recipename> <ingredlist> <listitem> <quantity>3</quantity> <itemdescription>chocolate syrup or chocolate fudge</itemdescription> </listitem> <listitem> <quantity>1</quantity> <itemdescription>nuts</itemdescription> </listitem> <listitem> <quantity>1</quantity> <itemdescription>cherry</itemdescription> </listitem> </ingredlist> <preptime>5 minutes</preptime> </recipe>
在這個問題中,你須要在給定的文本 XML 中,查找出給定模式 XML 的全部出現的位置。文本 XML 中的每一個標籤按照出現的順序編號,根節點的編號爲 1,例如上面的第一個 <listitem> 標籤的編號爲 4,文本和模式標籤有且僅有一個根節點,輸出每組匹配中,模式 XML 的根節點標籤在文本 XML 中的編號。
模式是相似這樣的字符串:<listitem><quantity></quantity></listitem>
這題目是要處理xml並匹配模式。這類題目首先咱們須要能方便的訪問它的每個節點,XML本深就是一種樹形結構,顯然咱們應該先建樹,採用tree-list的形式,而且按照層次的順序爲其標號。爲了建樹和描述這個xml,咱們數據結構設計以下:
class TreeType: def __init__(self, lab='', father=None, num=0): self.num = num self.lab = lab self.father = father self.son_list = []
其中num表示編號,lab是xml的標籤,father是父親節點,方便咱們建樹時,遇到</>返回到其父節點。son_list是當前節點的全部的子節點。
爲了方便處理,先建個虛擬的根節點(儘管本題說明了xml只有一個根節點,這樣作的好處是,你每一個節點均可以調用統一的插入或者返回上層節點的操做,不須要特別處理一開始的根節點),建樹按行掃描xml,遇到<>就爲當建立一個新的節點,而且添加描述信息,而後將當前節點指向這個新建的節點。若是遇到</>就退回到其父節點便可。當退回到虛擬的根節點的時候,代表xml讀取完成(這也是簡歷虛擬根節點的好處)。
建樹完成後,咱們對這棵樹進行dfs,按深度去查找是否存在題目給定的模式。須要注意到下面的這種特殊的狀況:
<a> <b> <c></c> <c></c> <c></c> </b> </a>
若是模式爲
<b><c></c></c>,
咱們DFS的時候要注意重複識別的問題,這樣的模式題目只算出現一次。此外,不要從本題的頁面直接複製輸入樣例。
import sys const_self = 1 class TreeType: def __init__(self, lab='', father=None, num=0): self.num = num self.lab = lab self.father = father self.son_list = [] def parse_line(line): labs = [] t_lab = [] lab_f = False for ch in line: if ch == '<': lab_f = True if lab_f: t_lab.append(ch) if ch == '>': lab_f = False labs.append(list(t_lab)) t_lab[:] = [] return labs def new_lab_to_tree(cn, r, cnt): node = TreeType(r, cn, cnt) cn.son_list.append(node) return node def finish_lab(cn, r): return cn.father def dfs(cn, mode, state, first_p, matched_p, fi): lab = ''.join(cn.lab) next_s = state if lab == ''.join(mode[state]): next_s += 1 else: next_s = 0 if next_s == 1: first_p = cn.num if next_s >= len(mode) / 2 and not fi: if not len(matched_p) or first_p != matched_p[-1]: matched_p.append(first_p) fi = True for son in cn.son_list: dfs(son, mode, next_s, first_p, matched_p, fi) def main(): node_cnt = 0 current_node = TreeType('', None, node_cnt) xml = [] while True: line = map(str, sys.stdin.readline().strip().split('\n'))[0] labs = parse_line(line) xml.append(labs) for lab in labs: if ''.join(lab).startswith('</'): current_node = finish_lab(current_node, lab) # r is used for verify else: node_cnt += 1 current_node = new_lab_to_tree(current_node, lab, node_cnt) if current_node.num == 0: break mode = parse_line(map(str, sys.stdin.readline().strip().split('\n'))[0]) matched_p = [] dfs(current_node, mode, 0, 0, matched_p, False) print len(matched_p) for p in matched_p: print p, if __name__ == '__main__': main()
<題目來源:百度2017秋招 原題連接-可在線提交(賽碼網)>
有一個含n字節的連續內存區域可能存在問題,工程師手中有一種檢查軟件,軟件每次運行能夠檢查一段連續內存區間。因爲檢查的區間長度越長,要花費的時間就越多,所以工程師但願可以在運行最多m次程序的狀況下,每次檢查的區間長度最大值最小,且檢查的區間的並集包含了全部出現的"1"。現給出內存的狀況(0表明該字節不須要檢查,1表明該字節須要檢查),求最小的區間最大長度。
須要注意到這類題目的重要信息:最小的區間最大長度,仔細閱讀這個題目以後咱們會發現,若是咱們從正面入手考慮,會考慮比較多的狀況,尤爲是既要考慮到這個最小的區間,又要考慮到使得其長度儘量的大,難度比較大。另外觀察到,這個題目的答案是一個已知的區間,答案的範圍不外乎就是整個內存區域的長度,或者在m足夠大的狀況,咱們能夠爲每一個「1」單獨檢查一次,這時的答案是1。
因爲答案是連續且單調遞增的,那麼咱們能夠考慮二分枚舉全部的答案,剩下的問題就是如何驗證這個答案是否正確了。顯然咱們從內存區域的一個方向開始後,碰到1就須要檢查,這個時候,按長度檢查便可。當前長度的區間檢查完後掃描內存,碰到1就繼續及檢查,若是超過m次,且還沒完成檢查,那麼證實這個答案不可行,咱們就縮小了答案的範圍。
import sys def test_scan(l_segment, i_segment_len, i_len, i_lim): i_cur_lf = 0 i_use = 0 b_allzero = True for i in range(i_segment_len): if '1' == l_segment[i]: b_allzero = False if not i_cur_lf: i_use += 1 i_cur_lf = i_len if i_cur_lf: i_cur_lf -= 1 if i_use <= i_lim: if i_len > 0 or (0 == i_len and b_allzero): return True return False if __name__ == '__main__': i_test_case = int(raw_input()) for scr in range(i_test_case): l_line = raw_input().split() i_segment_len = int(l_line[0]) i_exe_lim = int(l_line[1]) l_segment = list(raw_input()) i_top = i_segment_len i_bot = 0 while i_top >= i_bot: i_mid = (i_top + i_bot) / 2 if test_scan(l_segment, i_segment_len, i_mid, i_exe_lim): i_res = i_mid i_top = i_mid - 1 else: i_bot = i_mid + 1 print 'Case ' + str(scr + 1) + ': ' + str(i_res)
<題目來源: 百度2017秋招 原題連接-可在線提交(賽碼網)>
小A、小B、小C三人正組隊參加現場賽。小A剛過了一道大模擬,伸出手想看看幾點了,卻發現本身沒有帶表,隊友也沒有帶,由於你們平時是用手機看的。小A發現現場有一個電子顯示屏上面有時間。
電子顯示屏是一個7100的點陣,當前時間爲一個729的矩陣,在顯示屏上左右滾動,詳見樣例
數字0~9分別用7*6的矩陣表示以下
遺憾的是,小A眼睛高度近視,須要你念出時間給他聽...
因此如今給你一個這樣的點陣,輸出當前時間。
輸入
多組輸入數據,第一行是數據組數T(T≤1440)。
接下來是T組數據,每組數據是一個7100的點陣。輸入數據保證其中存在合法的729的點陣,詳見樣例。
輸出
對每組數據輸出一行答案,該行中輸出「Case #k: result」(對應第k組數據,冒號後有空格),result爲當前時間h:m。
這類題目主要難點在於字符串的處理,如何設計數據結構去存儲這個樣的一個點陣,而後是要利於咱們對這個點陣進行處理。
首先,咱們考慮如何識別點陣數字,其實這個裏面有一些特徵,咱們能夠耐心的去找出來,咱們能夠從須要數目多的開始入手:例如"8",咱們確保3個點的有無""就能夠識別。可是,整體我以爲仍是比較麻煩。容易出錯,還不太好排除問題。
個人方法就比較暴力,可是頗有效:把每一個數字的76的點陣存在代碼裏,取出7100點陣中的每一個數字,而後逐行按字符串比較便可。
剩下最後一個須要解決的問題是如何定位的問題,由於這個數碼從哪一列開始,並非固定的。觀察後,咱們發現經過定位「:」而後計算小時的開始,和分鐘的開始很方便,每一個數碼相對於":"的位置[-14, -7, 2, 9],至此這個問題也就完全解決了。
import sys const_board_row = 7 const_board_col = 100 template = [['******', '* *', '* *', '* *', '* *', '* *', '******'], [' *', ' *', ' *', ' *', ' *', ' *', ' *'], ['******', ' *', ' *', '******', '* ', '* ', '******'], ['******', ' *', ' *', '******', ' *', ' *', '******'], ['* *', '* *', '* *', '******', ' *', ' *', ' *'], ['******', '* ', '* ', '******', ' *', ' *', '******'], ['******', '* ', '* ', '******', '* *', '* *', '******'], ['******', ' *', ' *', ' *', ' *', ' *', ' *'], ['******', '* *', '* *', '******', '* *', '* *', '******'], ['******', '* *', '* *', '******', ' *', ' *', '******']] def compare_dig(board, col_begin, col_end): for i in range(10): match_f = True for row in range(7): # print ''.join(board[row][col_begin:col_end + 1]) if ''.join(board[row][col_begin:col_end + 1]) != ''.join(template[i][row]): match_f = False break if match_f: return i return -1 def main(): test_cases = map(int, sys.stdin.readline().strip().split())[0] for test_case in range(1, test_cases + 1): board = [['' for i in range(const_board_col)] for j in range(const_board_row)] for i in range(const_board_row): board[i] = map(str, sys.stdin.readline().split('\n'))[0] # local divide tag for i in range(const_board_col): cnt = 0 for j in range(const_board_row): if board[j][i] == '*': cnt += 1 if cnt == 2 and board[2][i] == '*' and board[4][i] == '*': dv_tag_col = i break dg_local = [-14, -7, 2, 9] rs = [] for i in range(4): rs.append(compare_dig(board, dv_tag_col + dg_local[i], dv_tag_col + dg_local[i] + 5)) hh = rs[0] * 10 + rs[1] mm = rs[2] * 10 + rs[3] print ('Case #{}: {}:{}').format(test_case, hh, mm) if __name__ == '__main__': main()