1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        一道 Google 的面試題

        共 321字,需瀏覽 1分鐘

         ·

        2020-09-25 16:25

        大家好,我是一行

        想進谷歌不會連這道題也不會吧


        面試題目是這樣的:


        假設(shè)第1個杯子的容量是A升,第2個杯子的容量B升,兩個杯子一開始都為空,現(xiàn)在有以下三種操作:

        1. FILL(i):將 i 杯子中的水倒?jié)M。

        2. DROP(i):將 i 杯子中的水全部倒出只??毡?。

        3. POUR(i,j):將杯子 i 中的水倒到杯子 j 中,若杯子 j 滿了或者杯子 i 已經(jīng)為空了則停止。

        如果你每次只能進行上面操作中的一種,如何使其中一個杯子的水容量恰好為C(C <= max(A,B))升?


        問題入手分析:


        當(dāng)A=3, B=5 C=4 時,初始時兩個杯子均為空,該如何操作?


        很容易得出依次需要進行的操作為:

        FILL(2),此時兩個杯子的水容量為:0,5

        POUR(2,1),此時兩個杯子的水容量為:3,2

        DROP(1),此時兩個杯子的水容量為:0,2

        POUR(2,1),此時兩個杯子的水容量為:2,0

        FILL(2),此時兩個杯子的水容量為:2,5

        POUR(2,1),此時兩個杯子的水容量為:3,4


        這就得到了容量為4的水。通過這個分析,我們能夠得到哪些啟發(fā)?


        • 因為 i 和 j 的取值都是1或者2, 所以對于某個狀態(tài),所執(zhí)行的操作總共有六種,下面會具體分析。

        • 對于某一個狀態(tài),我們下面有 6 種選擇,很明顯,解決這類問題比較好的辦法是廣度優(yōu)先遍歷(BFS)。而廣度優(yōu)先遍歷,所依賴的數(shù)據(jù)結(jié)構(gòu)便是隊列。


        假設(shè)目前2個杯子水的容量分別為 a 和 b,那么可以執(zhí)行的操作分別為:

        1、FILL(1)

        此時杯子1的水的容量變?yōu)锳,而杯子2的水的容量不發(fā)生變化。

        2、FILL(2)

        此時杯子2的水的容量變?yōu)锽,而杯子1的水的容量不發(fā)生變化。

        3、DROP(1)

        此時杯子1的水的容量變?yōu)?,而杯子2的水的容量不發(fā)生變化。

        4、DROP(2)

        此時杯子2的水的容量變?yōu)?,而杯子1的水的容量不發(fā)生變化。

        5、POUR(1,2)

        此種情況略微復(fù)雜,要分為兩種場景:

        1)、若杯子1中的水可以全部倒入杯子2中,即滿足a<=B-b,那么杯子1的水的容量變?yōu)?,杯子2的水的容量變?yōu)閍+b。

        2)、若杯子1中的水倒入杯子2中還會有剩余,即a>B-b,那么杯子1的水的容量變?yōu)?a-(B-b),杯子2的水的容量變?yōu)锽。

        6、POUR(2,1)

        此種情況同POUR(1,2),也要分為兩種場景:

        1)、若杯子2中的水可以全部倒入杯子1中,即滿足b<=A-a,那么杯子2的水的容量變?yōu)?,杯子1的水的容量變?yōu)閍+b。

        2)、若杯子2中的水倒入杯子1中還會有剩余,即b>A-a,那么杯子2的水的容量變?yōu)?b-(A-a),杯子1的水的容量變?yōu)锳。


        所以,對于某個狀態(tài),我們需要廣度優(yōu)先遍歷上述6種操作,當(dāng)遇到某個杯子的容量為C時,停止廣度優(yōu)先遍歷,遍歷的過程可以用下圖簡單表示:



        明白了上述原理,就可以考慮隊列節(jié)點的數(shù)據(jù)結(jié)構(gòu)了:


        對于每個狀態(tài),我們需要存儲的信息包括:當(dāng)前杯子1的水的容量a,當(dāng)前杯子2的水的容量b,由上個狀態(tài)到本狀態(tài)執(zhí)行的操作,以及上一個狀態(tài)的信息(需要由此獲得所有的操作流程)。Python代碼如下:


        class Node:
        ? ?# a:當(dāng)前狀態(tài)杯子1的水的容量
        ? ?
        # b:當(dāng)前狀態(tài)杯子2的水的容量
        ? ?
        # pre 上一個狀態(tài)
        ? ?
        # action上一個狀態(tài)到本狀態(tài)執(zhí)行的操作
        ? ?
        def __init__(self, a, b, pre, action):
        ? ? ? ?self.a = a
        ? ? ? ?self.b = b
        ? ? ? ?self.pre = pre
        ? ? ? ?self.action = action


        對于BFS,理解了上述6種操作就很簡單了,在這里特別要注意的是避免死循環(huán),所以在入隊列的時候只入之前沒出現(xiàn)過的狀態(tài),用數(shù)組visted 記錄已經(jīng)存在過的狀態(tài),存在過的狀態(tài)就不入隊列。Python代碼如下:


        def BFS(A, B, C):
        ? ?"""
        ? ?
        通過廣度搜索來計算容量為C的水
        ? ?
        :param A: 容量為A的杯子1
        ? ?
        :param B: 容量為B的杯子2
        ? ?
        :param C: 容量為C的水
        ? ?
        :return:
        ? ?"""

        ? ?
        # visited 記錄是否有過相關(guān)的容器組合,如果沒有才塞入隊列,避免死循環(huán)
        ? ?
        maxC = max([A,B])
        ? ?visited = [[0 for i in range(maxC + 1)] for i in range(maxC + 1)]
        ? ?# 初始化隊列
        ? ?
        q = Queue.Queue()
        ? ?# 初始化隊列的第一個節(jié)點并放入隊列
        ? ?
        node = Node(0, 0, None, "0")
        ? ?q.put(node)

        ? ?while not q.empty():
        ? ? ? ?cur = q.get()

        ? ? ? ?# FILL(1)
        ? ? ? ?
        a = A
        ? ? ? ?b = cur.b
        ? ? ? ?pre = cur
        ? ? ? ?action = "FILL(1)"

        ? ? ? ?
        if not visited[a][b]:
        ? ? ? ? ? ?node = Node(a, b, pre, action)
        ? ? ? ? ? ?q.put(node)
        ? ? ? ? ? ?visited[a][b] = 1

        ? ? ? ?
        if a == C or b == C:
        ? ? ? ? ? ?return True, node

        ? ? ? ?# FILL(2)
        ? ? ? ?
        a = cur.a
        ? ? ? ?b = B
        ? ? ? ?pre = cur
        ? ? ? ?action = "FILL(2)"

        ? ? ? ?
        if not visited[a][b]:
        ? ? ? ? ? ?node = Node(a, b, pre, action)
        ? ? ? ? ? ?q.put(node)
        ? ? ? ? ? ?visited[a][b] = 1

        ? ? ? ?
        if a == C or b == C:
        ? ? ? ? ? ?return True, node

        ? ? ? ?# DROP(1)
        ? ? ? ?
        a = 0
        ? ? ? ?
        b = cur.b
        ? ? ? ?pre = cur
        ? ? ? ?action = "DROP(1)"

        ? ? ? ?
        if not visited[a][b]:
        ? ? ? ? ? ?node = Node(a, b, pre, action)
        ? ? ? ? ? ?q.put(node)
        ? ? ? ? ? ?visited[a][b] = 1

        ? ? ? ?
        if a == C or b == C:
        ? ? ? ? ? ?return True, node

        ? ? ? ?# DROP(2)
        ? ? ? ?
        a = cur.a
        ? ? ? ?b = 0
        ? ? ? ?
        pre = cur
        ? ? ? ?action = "DROP(2)"

        ? ? ? ?
        if not visited[a][b]:
        ? ? ? ? ? ?node = Node(a, b, pre, action)
        ? ? ? ? ? ?q.put(node)
        ? ? ? ? ? ?visited[a][b] = 1

        ? ? ? ?
        if a == C or b == C:
        ? ? ? ? ? ?return True, node

        ? ? ? ?# POUR(1,2)
        ? ? ? ?
        if cur.a < B - cur.b:
        ? ? ? ? ? ?a = 0
        ? ? ? ? ? ?
        b = cur.b + cur.a
        ? ? ? ? ? ?pre = cur
        ? ? ? ? ? ?action = "POUR(1,2)"
        ? ? ? ?
        else:
        ? ? ? ? ? ?a = cur.a - (B - cur.b)
        ? ? ? ? ? ?b = B
        ? ? ? ? ? ?pre = cur
        ? ? ? ? ? ?action = "POUR(1,2)"

        ? ? ? ?
        if not visited[a][b]:
        ? ? ? ? ? ?node = Node(a, b, pre, action)
        ? ? ? ? ? ?q.put(node)
        ? ? ? ? ? ?visited[a][b] = 1

        ? ? ? ?
        if a == C or b == C:
        ? ? ? ? ? ?return True, node

        ? ? ? ?# POUR(2,1)
        ? ? ? ?
        if cur.b < A - cur.a:
        ? ? ? ? ? ?a = cur.b + cur.a
        ? ? ? ? ? ?b = 0
        ? ? ? ? ? ?
        pre = cur
        ? ? ? ? ? ?action = "POUR(2,1)"
        ? ? ? ?
        else:
        ? ? ? ? ? ?a = A
        ? ? ? ? ? ?b = cur.b - (A - cur.a)
        ? ? ? ? ? ?pre = cur
        ? ? ? ? ? ?action = "POUR(2,1)"

        ? ? ? ?
        if not visited[a][b]:
        ? ? ? ? ? ?node = Node(a, b, pre, action)
        ? ? ? ? ? ?q.put(node)
        ? ? ? ? ? ?visited[a][b] = 1

        ? ? ? ?
        if a == C or b == C:
        ? ? ? ? ? ?return True, node

        ? ?return False, None


        還需要一個代碼,獲取一步步操作的流程,這里,由于拿到的是最后一個節(jié)點,所以要根據(jù)pre逆向?qū)ふ蚁嚓P(guān)的action,并存儲在列表中。最后,將結(jié)果逆向輸出:


        def ShowResult(node):
        ? ?"""
        ? ?
        根據(jù)最終節(jié)點選擇前面的節(jié)點,并打印action
        ? ?
        :param node:
        ? ?
        :return:
        ? ?"""
        ? ?
        L = []
        ? ?while node.pre is not None:
        ? ? ? ?L.append(node.action)
        ? ? ? ?node = node.pre

        ? ?inverseL = L[::-1]

        ? ?for item in inverseL:
        ? ? ? ?print item


        有了上述代碼,就可以設(shè)置不同的容量值來進行測試了:


        if __name__ == '__main__':
        ? ?A = 3
        ? ?
        B = 5
        ? ?
        C = 4
        ? ?
        flag, node = BFS(A, B, C)
        ? ?if flag is True:
        ? ? ? ?ShowResult(node)
        ? ?else:
        ? ? ? ?print "Impossible"


        現(xiàn)在想想,一步步分析下來,題目就沒有當(dāng)初第一眼看到題目時那么難了吧?所以,當(dāng)遇到難題時,一定要從小問題入手,逐步化解,由淺入深


        推薦閱讀

        (點擊標(biāo)題可跳轉(zhuǎn)閱讀)

        華為提出十大數(shù)學(xué)挑戰(zhàn)!解出一個就是年薪百萬!

        Jupyter 插件太好用了

        圖解 SQL


        轉(zhuǎn)了嗎
        ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ??
        ? ? ? ? ? ? ? ? ? ? ? ? ? ?贊了嗎
        在看嗎
        瀏覽 58
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            三级午夜片 | 老头侵犯小男生肉h | 黄页网站视频 | 亚洲高清免费 | 一区无码| 99久久久| 小俊好湿好紧太爽了视频 | 青青青青操| 91麻豆精品A片国产在线观看 | 搞日日韩极品女人 |