在Cracking the Coding Interview, Fourth Edition中,存在这样的问题:
马戏团正在设计一个由人站立组成的塔楼例程 在另一个人的肩膀上面出于实际和美学的原因, 每个人都必须比他下面的人更短更轻 或者考虑到马戏团中每个人的身高和体重, 写一种方法来计算最大可能的人数 这样的塔。
示例:输入(ht,wt):( 65,100)(70,150)(56,90) (75,190)(60,95)(68,110)
输出:最长的塔长6和 包括从上到下:(56,90)(60,95)(65,100)(68,110) (70,150)(75,190)
以下是本书中的解决方案
步骤1首先按高度排序所有项目,然后按重量排序这意味着如果所有高度都是唯一的,那么项目将按其高度排序如果高度相同,则项目将按其重量排序
步骤2找到包含增加高度和增加权重的最长序列 为此,我们:
a)从序列的开头开始目前,max_sequence为空
b)如果对于下一个项目,身高和体重不大于前一个项目,我们将此项目标记为“不合格”
c)如果找到的序列中的项目多于“最大序列”,则变为“最大序列”
d)之后,从“不合适的项目”重复搜索,直到我们到达原始序列的末尾
我对其解决方案有一些疑问。
Q1
我认为这个解决方案是错误的。
例如
(3,2) (5,9) (6,7) (7,8)
显然,(6,7)
是一个不合适的项目,但(7,8)
怎么样?根据解决方案,它并不适合,因为它的h和w比(6,7)
更大,但是,它不能被考虑到序列中,因为(7,8)
不适合(5,9)
。< / p>
我是对的吗?
如果我是对的,修复是什么?
Q2
我相信即使上述解决方案有解决方案,解决方案的风格也至少会导致O(n^2)
,因为根据步骤2-d,它需要反复迭代。
那么有可能有一个O(nlogn)解决方案吗?
答案 0 :(得分:1)
您可以使用动态编程解决问题。
按高度对剧团进行排序。为简单起见,假设所有高度h_i和权重w_j都是不同的。因此,h_i是一个递增的序列。
我们计算一个序列T_i,其中T_i是一个塔,其中人i位于最大大小的顶部。 T_1只是{1}。我们可以从早期的T_j中推断出后续的T_k - 找到可以取k个权重的最大塔T_j(w_j&lt; w_k)并在其上站立。
该剧团最大的塔楼是T_i中最大的塔楼。
此算法需要O(n ** 2)时间,其中n是剧团的基数。
答案 1 :(得分:0)
我自己试图解决这个问题,并不是要给出“现成的解决方案”,但仍然给予,更多的是检查我自己的理解,以及我的代码(Python)是否正常并适用于所有测试用例。我尝试了3个案例,似乎正确的答案。
#!/usr/bin/python
#This function takes a list of tuples. Tuple(n):(height,weight) of nth person
def htower_len(ht_wt):
ht_sorted = sorted(ht_wt,reverse=True)
wt_sorted = sorted(ht_wt,key=lambda ht_wt:ht_wt[1])
max_len = 1
len1 = len(ht_sorted)
i=0
j=0
while i < (len1-1):
if(ht_sorted[i+1][1] < ht_sorted[0][1]):
max_len = max_len+1
i=i+1
print "maximum tower length :" ,max_len
###Called above function with below sample app code.
testcase =1
print "Result of Test case ",testcase
htower_len([(5,75),(6.7,83),(4,78),(5.2,90)])
testcase = testcase + 1
print "Result of Test case ",testcase
htower_len([(65, 100),(70, 150),(56, 90),(75, 190),(60, 95),(68, 110)])
testcase = testcase + 1
print "Result of Test case ",testcase
htower_len([(3,2),(5,9),(6,7),(7,8)])
答案 2 :(得分:0)
例如
(3,2)(5,9)(6,7)(7,8)
显然,(6,7)是一个不合适的项目,但是如何(7,8)?
在回答你的问题时 - 算法首先以3,2开始运行,并将序列(3,2)(5,9)标记为(6,7)和(7,8)为不合格。
然后再次开始(6,7)(第一次不适合)并得到(6,7)(7,8),这就得到答案2.因为没有更多“不合适”的项目,序列终止,最大长度为2。
答案 3 :(得分:0)
首先按高度和重量对数组进行排序后,如果我们抓住数组中剩余的任何元组(以及可能的后续元组),我的代码将检查最大的塔是什么。为了避免重新计算子问题,solution_a
用于存储input_array
尾部的最佳最大长度。
beginning_index
是我们可以考虑从中获取元素的索引(我们可以考虑在人类堆栈上可以考虑下方的人的索引),beginning_tuple
指的是元素/更高层的人。
此解决方案在O(nlogn)中运行以进行排序。使用的空间是solution_a
数组的O(n)和input_array
的副本。
def determine_largest_tower(beginning_index, a, beginning_tuple, solution_a):
# base case
if beginning_index >= len(a):
return 0
if solution_a[beginning_index] != -1: # already computed
return solution_a[beginning_index]
# recursive case
max_len = 0
for i in range(beginning_index, len(a)):
# if we can grab that value, check what the max would be
if a[i][0] >= beginning_tuple[0] and a[i][1] >= beginning_tuple[1]:
max_len = max(1 + determine_largest_tower(i+1, a, a[i], solution_a), max_len)
solution_a[beginning_index] = max_len
return max_len
def algorithm_for_human_towering(input_array):
a = sorted(input_array)
return determine_largest_tower(0, a, (-1,-1), [-1] * len(a))
a = [(3,2),(5,9),(6,7),(7,8)]
print algorithm_for_human_towering(a)
答案 4 :(得分:0)
这是另一种用代码解决问题的方法;
算法
排序数组: [(56, 90), (60, 95), (65, 100), (68, 110), (70, 150), (75, 190)]
为什么最长的权重子序列是答案? 人是按身高增加的, 所以当我们发现一个人的子序列也增加了权重时 这些被选中的人会满足我们的要求,因为他们的身高和体重都是递增的,因此可以组成一个人塔。
<块引用>例如: [(56, 90) (60,95) (65,100) (68,110) (70,150) (75,190)]
高效实施
在附加的实现中,我们维护了一个递增数字的列表,并使用 bisect_left
来查找正确的插入索引。
请注意; longest_increasing_sequence
方法生成的序列可能不是实际的最长子序列,但是,它的长度 - 肯定是最长递增子序列的长度。
请参阅Longest increasing subsequence Efficient algorithms了解更多详情。
总时间复杂度为 O(n log(n))。
代码
from bisect import bisect_left
def human_tower(height, weight):
def longest_increasing_sequence(A, get_property):
lis = []
for i in range(len(A)):
x = get_property(A[i])
i = bisect_left(lis, x)
if i == len(lis):
lis.append(x)
else:
lis[i] = x
return len(lis)
# Edge case, no people
if 0 == len(height):
return 0
# Creating array of heights and widths
people = [(h, w) for h, w in zip(height, weight)]
# Sorting array first by height and then by width
people.sort()
# Returning length longest increasing sequence
return longest_increasing_sequence(people, lambda t : t[1])
assert 6 == human_tower([65,70,56,75,60,68], [100,150,90,190,95,110])