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: . For example, 1729 is the smallest taxicab number:
. Design an algorithm to find all taxicab numbers with a, b, c, and d less than n.
- Version 1: Use time proportional to
and space proportional to
.
- Version 2: Use time proportional to
and space proportional to
.
Taxicab numbers: taxicab number是可以以两种不同方式表示为两个正整数立方之和的整数,即:。例如,1729即是最小的taxicab number,
。设计一个算法找到所有满足a,b,c,d小于n的taxicab number。
- 版本1:算法时间复杂度为
,空间复杂度为
- 版本2:算法时间复杂度为
,空间复杂度为
Solutions:
Version 1:
计算所有小于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,我们观察矩阵,
可以发现:
- 矩阵是由左向右、由上到下逐渐增大的;
- 同一行、同一列的数值必不相同。
首先为了节省时间,我们不再考虑下三角矩阵
接下来我们需要做的,是对上三角区域进行排序,保证数值按照从大到小的顺序输出。
使用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