我正在从名为codefights的网站解决一些问题,最后解决的问题是关于二叉树的问题:
考虑一个特殊的工程师和医生家庭。这个家庭有 以下规则:
每个人都有两个孩子。工程师的第一个孩子是 工程师和第二个孩子是博士。医生的第一个孩子 是医生,第二个孩子是工程师。各代人 医生和工程师从工程师开始。
我们可以使用此图表示情况:
E / \ E D / \ / \ E D D E / \ / \ / \ / \ E D D E D E E D
鉴于一个人在上面的祖先树中的水平和位置, 找到这个人的职业。注意:在这棵树中,第一个孩子是 被视为左孩子,第二 - 被视为正确。
由于存在一些空间和时间限制,解决方案不能基于实际构建树直到所需级别并检查哪个元素位于所要求的位置。到现在为止还挺好。我用python编写的解决方案是:
def findProfession(level, pos):
size = 2**(level-1)
shift = False
while size > 2:
if pos <= size/2:
size /= 2
else:
size /= 2
pos -= size
shift = not shift
if pos == 1 and shift == False:
return 'Engineer'
if pos == 1 and shift == True:
return 'Doctor'
if pos == 2 and shift == False:
return 'Doctor'
if pos == 2 and shift == True:
return 'Engineer'
当它解决问题时,我可以访问其他使用的解决方案,我对这个感到惊讶:
def findProfession(level, pos):
return ['Engineer', 'Doctor'][bin(pos-1).count("1")%2]
更多的是,我不理解它背后的逻辑,所以我们来到了这个问题。有人可以向我解释这个算法吗?
答案 0 :(得分:3)
让我们用以下方式对树的节点进行编号:
1)根号为1
2)节点x的第一个子节点号为2 * x
3)节点x的第二个子节点号为2 * x + 1
现在,请注意,每次去第一个孩子时,职业都保持不变,并且在节点的二进制表示中添加0。 每次你去第二个孩子时,职业都会翻转,你会在二进制表示中添加1。
示例:让我们找到第4级中第4个节点的职业(问题中图中的最后一级)。首先我们从数字1的根开始,然后我们去第一个数字为2的孩子(10二进制)。之后我们转到2的第二个孩子,即5(101二进制)。最后,我们转到5的第二个孩子,即11(1011二进制)。
请注意,我们只从一个等于1的位开始,然后我们添加到二进制表示中的每1位都会翻转专业。因此,我们翻转专业的次数等于(位数等于1) - 1.此数量的平价决定了专业。
这引出了以下解决方案:
X = [2 ^(level-1)+ pos - 1]
中的位数等于1Y =(X-1)mod 2
如果Y为0则答案是“工程师” 否则答案是“医生”
由于2 ^(level-1)是2的幂,它恰好有一位等于1,因此你可以写:
X = [pos-1]
中的位数等于1Y = X mod 2
这与您在问题中提到的解决方案相同。
答案 1 :(得分:0)
这种类型的序列称为Thue-Morse sequence。使用同一棵树,这是为什么它给出正确答案的演示:
p
是0索引位置
b
是p
c
是b
中的1的数目
p0
E
b0
c0
/ \
p0 p1
E D
b0 b1
c0 c1
/ \ / \
p0 p1 p2 p3
E D D E
b0 b1 b10 b11
c0 c1 c1 c2
/ \ / \ / \ / \
p0 p1 p2 p3 p4 p5 p6 p7
E D D E D E E D
b0 b1 b10 b11 b100 b101 b110 b111
c0 c1 c1 c2 c1 c2 c2 c3
c
对于工程师来说始终是偶数,对于Doctor来说总是奇数。因此:
index = bin(pos-1).count('1') % 2
return ['Engineer', 'Doctor'][index]