不使用比較和條件判斷實現min函式的一種方法
阿新 • • 發佈:2022-05-06
不使用比較和條件判斷實現min函式,引數為兩個32位無符號int。
面試的時候遇到的題目,感覺很有意思。
搜了一下多數現有的解法都是僅有兩種限制之一,即要麼僅要求不能使用比較,要麼僅要求不能使用條件判斷,於是打算寫一下一種能兼顧兩種限制的實現方法。
需要注意的是,條件判斷當然也包含三目表示式、switch-case語句甚至abs等隱含條件分支的語法糖或標準庫函式,除非能夠不借助條件分支實現(例如沒有條件分支的abs:參考連結)。
Solution
基本思想很簡單,在二進位制表示下從高位開始逐位比較,相同的位置可以直接忽略,直到遇到第一個不相同的位置,大小關係就決定了。譬如比較
a=011010 b=010110
時,從高位至低位比較到第三位時兩數不同。此時必定是較大者 a 此位為 1,較小者 b 此位為 0,記此位為符號位 sign_a, sign_b
。
實際上此時我們已經分辨出兩數的大小,再想辦法將較大者的資訊抹掉即可。方法是分別將 a, b 剩餘的每一位都與符號位相或,此時較大者 a 後半部分變為全 1,而較小者 b 不變,將兩者相與,其結果等於 b,求得min。
在實際實現時可以使用位運算消除條件分支,具體可以參考程式碼。
""" myMin(0b011010, 010110) (1) 011010 A 010110 B ^ same 0 vs. 0 (2) 011010 A 010110 B ^ same 1 vs. 1 (3) 011010 A 010110 B ^ diff, sign_A=1, sign_B=0 (4) 011110 A' 010110 B' ^ A_i |= sign_A, B_i |= sign B (5)(6) 011111 A'' 010110 B'' ^ A_i |= sign_A, B_i |= sign B A'' & B'' = B """ def myMin(a, b): found = 0 sign_a, sign_b = 0, 0 for i in range(32, -1, -1): bit = 1 << i xa, xb = (a & bit) >> i, (b & bit) >> i # if not found: # d = xa ^ xb # else: # d = 0 d = (not found) & (xa ^ xb) # if xa ^ xb == 1: # found = 1 found |= xa ^ xb # if d: # sign_a, sign_b = xa, xb sign_a |= d & xa sign_b |= d & xb a |= sign_a * bit b |= sign_b * bit return a&b # 用於生成隨機測試用例測試正確性 import random, time loop = 0 MAX = 1<<32 while True: a, b = random.randint(0, MAX), random.randint(0, MAX) if myMin(a, b) != min(a, b): print(f"min({a}, {b}) = {min(a, b)} != {myMin(a, b)}") break loop += 1 print(loop, end='\r') time.sleep(0.001)