Princeton Algorithm Priority Queues Practice Quiz ---- taxicab number

Questions:

Taxicab numbers. A taxicab number is an integer that can be expressed as the sum of two cubes of positive integers in two different ways: a^3 + b^3 = c^3 + d^3. For example, 1729 is the smallest taxicab number: 9^3 + 10^3 = 1^3 + 12^3. Design an algorithm to find all taxicab numbers with a, b, c, and d less than n.

  • Version 1: Use time proportional to n^2 \log n and space proportional to n^2.
  • Version 2: Use time proportional to n^2 \log n and space proportional to n.

Taxicab numbers:  taxicab number是可以以两种不同方式表示为两个正整数立方之和的整数,即:a^3 + b^3 = c^3 + d^3。例如,1729即是最小的taxicab number,9^3 + 10^3 = 1^3 + 12^3。设计一个算法找到所有满足a,b,c,d小于n的taxicab number。

  • 版本1:算法时间复杂度为n^2 \log n,空间复杂度为n^2
  • 版本2:算法时间复杂度为n^2 \log n,空间复杂度为n

Solutions:

Version 1:

计算所有小于n的整数两两的立方之和,使用n^2大小的数组储存结果,并使用排序算法进行排序。如利用快速排序,原时间复杂度为~~k \log k,当数组大小为n^2时,时间复杂度为~n^2 \log n^2 = 2 n^2 \log n

Code (Python3):

def taxicab_num_1(N):
    sum = []
    for i in range(N):
        for j in range(i, N):
           sum.append((i, j, i*i*i + j*j*j))
    sum.sort(key=lambda x:x[2])

    for i in range(1, sum.__len__()):
        if(sum[i][2] == sum[i-1][2]):
            print('%d: %d^3 + %d^3 = %d^3 + %d^3'
                  % (sum[i][2], sum[i-1][0], sum[i-1][1], sum[i][0], sum[i][1]))

taxicab_num_1(32)

Version 2:

这里令n=5,我们观察矩阵M[i][j] = i^3 + j^3

可以发现:

  1. 矩阵是由左向右、由上到下逐渐增大的;
  2. 同一行、同一列的数值必不相同。

首先为了节省时间,我们不再考虑下三角矩阵

接下来我们需要做的,是对上三角区域进行排序,保证数值按照从大到小的顺序输出。

使用Priority Queue的数据结构(以下简称PQ),需要执行的算法如下


初始化:将右下角数值放入PQ

循环重复:

从PQ pop出最大值

如果该值在上图中的上面的值和左边的值满足以下条件:1)未被处理过;2)同一列或同一行中没有数值在PQ内。则将该值插入PQ

直到PQ为空为止


需要注意的是:上面的矩阵M只是为了说明算法,并不需要在内存中创建

动态过程如下图所示:

由图示可以看出:250、189、152、133、128、126、125、91、……数值被以从大到小的顺序依次pop出

Code:

def taxicab_num_2(N):
    pq = PQ()
    row_mark = [0]*N
    col_mark = [0]*N

    pq.insert([N-1, N-1, ((N-1)**3)*2])
    row_mark[N-1] = 1
    col_mark[N-1] = 1
    last = [-1,-1,-1]
    while(not pq.isEmpty()):
        cur = pq.delMax()
        i = cur[0]
        j = cur[1]
        row_mark[i] = 0
        col_mark[j] = 0

        if (i - 1 >= 0 and row_mark[i - 1] == 0 and j >= i-1):
            pq.insert([i - 1, j, (i-1) ** 3 + j ** 3])
            row_mark[i-1] = 1
            col_mark[j] = 1
        if (j - 1 >= 0 and col_mark[j - 1] == 0 and j-1 >= i):
            pq.insert([i, j - 1, i ** 3 + (j-1) ** 3])
            row_mark[i] = 1
            col_mark[j-1] = 1

        if(cur[2] == last[2]):
            print('%d: %d^3 + %d^3 = %d^3 + %d^3'
                  % (cur[2], last[0], last[1], cur[0], cur[1]))
        last = cur


taxicab_num_2(32)

附:Version2用到的PQ(Priority Queue)代码:

class PQ:
    def __init__(self):
        self.values = []

    def exch(self, i, j):
        self.values[i], self.values[j] = self.values[j], self.values[i]

    def swim(self, k):
        while(k > 0 and self.values[k][2] > self.values[math.ceil(k/2)-1][2]):
            self.exch(k, math.ceil(k/2)-1)
            k = math.ceil(k/2)-1

    def insert(self, event):
        self.values.append(event)
        self.swim(len(self.values) - 1)

    def sink(self, k):
        while((2*k+1) < len(self.values)):
            if(2*k+2 >= len(self.values)): j = 2*k+1
            elif(self.values[2*k+1][2] > self.values[2*k+2][2]): j = 2*k+1
            else: j = 2*k+2
            if(self.values[k][2] < self.values[j][2]):
                self.exch(k,j)
                k = j
            else:
                break

    def delMax(self):
        self.exch(0, len(self.values) - 1)
        max = self.values.pop(len(self.values) - 1)
        self.sink(0)
        return max

    def isEmpty(self):
        return len(self.values) == 0

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值