找出假币

假设假币比真币轻,使用分2堆称重和分3堆称重的方法分别找出假币,同时比较两种方法的称重次数。

产生含假币的金币堆​

def genCoins(coinNum, fakeCoin):

    coins = [1] * coinNum

    coins[fakeCoin] = 0

    return coins

称出一堆金币重量​

def weighCoins(coins, beg, end):

s = 0

for i in range(beg, end):

    s += coins[i]

return s

分2堆找出​

def weighBy2(coins, beg, end, times=0):

    times += 2

    # 只剩一个返回​

    if end - beg == 1:

        print "weigh times: %s" % times

        return beg

    cnum = end - beg

    f = cnum / 2

    w1 = weighCoins(coins, beg, beg + f)

    w2 = weighCoins(coins, beg + f, beg + f * 2)

    # 继续称较轻的一堆​

    if w1 < w2:

        return weighBy2(coins, beg, beg + f, times)

    elif w1 > w2:

        return weighBy2(coins, beg + f, beg + f * 2, times)

    else:

        # 相等时就是最后一个​

        return end-1

def weighFakeCoinBy2(coins):

    return weighBy2(coins, 0, len(coins))

分3堆找出​

def weighFakeCoinBy3(coins):

    return weighBy3(coins, 0, len(coins))

def weighBy3(coins, beg, end, times=0):

    times += 2

    if end - beg == 1:

        print "weigh times: %s" % times

        return beg

    # if coins num is not even,plus 1 coin before beg or after end

    cnum = end - beg

    f = cnum / 3

    if f == 0:

        f = 1

    w1 = weighCoins(coins, beg, beg + f)

    w2 = weighCoins(coins, beg + f, beg + f * 2)

    if w1 < w2:

        return weighBy3(coins, beg, beg + f, times)

    elif w1 > w2:

        return weighBy3(coins, beg + f, beg + f * 2, times)

    else:

        return weighBy3(coins, beg + f * 2, end, times)

测试代码

class test(unittest.TestCase):

    def testGenCoins(self):

        fakeCoin = 9

        coinNum = 10

        coins = genCoins(coinNum, fakeCoin)

        for i in range(coinNum):

            if i == fakeCoin:

                self.assertEqual(coins[i], 0, "testGenCoins failed")

            else:

                self.assertEqual(coins[i], 1, "testGenCoins failed")

    def testWeigh(self):

        fakeCoin = 2

        coinNum = 3000000

        self.assertEqual(weighFakeCoinBy2(genCoins(coinNum, fakeCoin)), fakeCoin)

        self.assertEqual(weighFakeCoinBy3(genCoins(coinNum, fakeCoin)), fakeCoin)

if __name__ == '__main__':

    unittest.main()

分2堆的复杂度log2N,3堆是log3N。分3堆更快的原因在于比分2堆更快地减小的问题的规模。因为分为3堆后,只要比较一次,如果2小堆相等,则假币在第3堆中;如果不等,假币就在质量较大的一堆中。

点赞