python前缀_python – 前缀和算法

我试图抓住前缀总和概念背后的想法,看看由Codility here在前缀总课中提出的例子(蘑菇选择器问题)

我的理解是整个概念基于简单的属性,其中在数组A的两个位置A(pos_left,pos_right)之间找到所有元素的总和,使用第二个数组P,其中所有元素被连续求和并且搜索到的位置总和计算为

value(P(pos_right 1)) – 值(P(pos_left)).

A 1 2 3 4 5 6

P 0 1 3 6 10 15 21

sum of all elements between A[2] and A[5] = 3+ 4 + 5 = 12

or using the prefix sums" P[5+1] - P[2] = 15 -3 = 12

The problem

There is a street with mushroom at every place represented

by a non-empty vector. Given the initial position of a picker and its

movement range, possible maximum number of mushrooms to collect is

looked for.

看一下这个例子,我不明白循环构造背后的逻辑.任何人都可以澄清这种算法的机制吗?

其次,我发现这个例子中的positoin索引非常混乱和麻烦.通常的做法是将前缀加上的矢量“移位”在开始时为零吗? (事实上​​,向量中的计数元素从python中的0开始,因为已经引起了一些混乱).

解决方案

def prefix_sums(A):

n = len(A)

P = [0] * (n + 1)

for k in xrange(1, n + 1):

P[k] = P[k - 1] + A[k - 1]

return P

def count_total(P, x, y):

return P[y + 1] - P[x]

# A mushroom picker is at spot number k on the road and should perform m moves

def mushrooms(A, k, m):

n = len(A)

result = 0

pref = prefix_sums(A)

for p in xrange(min(m, k) + 1): # going left

left_pos = k - p

right_pos = min(n - 1, max(k, k + m - 2 * p))

result = max(result, count_total(pref, left_pos, right_pos))

for p in xrange(min(m + 1, n - k)):

right_pos = k + p

left_pos = max(0, min(k, k - (m - 2 * p)))

result = max(result, count_total(pref, left_pos, right_pos))

return result

我为一个小数组运行了一些例子A = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, 20],选择位置k = 5和范围m = 3.我不明白创建两个循环检查范围的逻辑.

我得到循环的以下参数

(p=, left_pos=, right_pos=)

loop 1 (0,5,8), (1,4,6),(2,3,5),(3,2,5)

loop 2 (0,2,5), (1,4,6), (2,5,7), (3,5,8)

rangies各不相同.为什么?

用于调试的版本

def mushrooms2(A, k, m):

n = len(A)

result = 0

pref = prefix_sums(A)

l1 =min(m, k) + 1

print 'loop p in xrange(min(m, k) + 1): %d' % l1

for p in xrange(min(m, k) + 1):

print 'p %d' % p

print 'A= %r' % A

print 'pref= %r' % pref

left_pos = k - p

right_pos = min(n - 1, max(k, k + m - 2 * p))

result = max(result, count_total(pref, left_pos, right_pos))

print 'left_pos = k - p= %d' % left_pos

print 'right_pos= min(n-1,max(k,k+m-2*p))= %d' % right_pos

print 'max'

print '(result %d' % result

print 'count_total(pref, left_pos, right_pos)) %r, %r, %r, %r' % (pref,left_pos, right_pos,count_total(pref, left_pos, right_pos))

print 'result= %d' % result

print 'next p'

l2=min(m + 1, n - k)

print 'loop xrange(min(m + 1, n - k)): %d' % l2

for p in xrange(min(m + 1, n - k)):

print 'p %d' % p

print 'A= %r' % A

print 'pref= %r' % pref

right_pos = k + p

left_pos = max(0, min(k, k - (m - 2 * p)))

result = max(result, count_total(pref, left_pos, right_pos))

print 'right_pos = k + p= %d' % right_pos

print 'left_pos = max(0, min(k, k - (m - 2 * p)))= %d' % left_pos

print 'max'

print '(result %d' % result

print 'count_total(pref, left_pos, right_pos)) %r, %r, %r, %r' % (pref,left_pos, right_pos,count_total(pref, left_pos, right_pos))

print 'result= %d' % result

print 'next p'

print 'result %d' % result

return result

解决方法:

你并不是唯一一个认为循环结构是反直觉的,因为我不得不花费几分钟时间.这是我想出来的.

现在,您提供的链接中的解决方案进一步详细说明了最佳策略是走在路径上,以便只改变方向一次.以这种方式,人们能够覆盖具有左端点和右端点的范围,left_pos和right_pos似乎代表.

至于循环的细节,不是根据循环变量(即p)来考虑循环,而是更容易确定循环过程中的变化以及如何使用p.否则,弄清楚那些最小和最大表达式中的内容在开始时似乎有点过于奇特.

例如,在第一个循环中,不是弄清楚该范围代表什么,而是尝试left_pos如何受到不同值p得到的影响.经过一番思考后,人们注意到left_pos以符合可能的左端点的方式发生了变化.

具体地,当p为0时,左端点是起始索引(即k),当p是min(m,k)时,则它是0(即,如果k >左转进行p动作.

>改变方向,然后向右移动p移动到达起点.

>使用剩余的(m – 2p)移动向右移动.

第二个循环只是第一个循环的反映,你可以通过调整我对第一个循环的解释来解释它.

至于你的第二个问题,我认为通常的做法是转移前缀和数组的索引.我通常在在线竞赛中使用这种方法进行竞争性编程,我在Python中使用的前缀和数组的实现如下所示.

def prefix_sums(A):

n = len(A)

P = [0] * n

P[0] = A[0]

for k in xrange(1, n):

P[k] = P[k - 1] + A[k]

return P

def count_total(P, x, y):

return P[y] - P[x - 1]

我对上述实现的直觉是:在P [x]处,我们得到包含和A [0] A [1] … A [x].

标签:python,algorithm

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值