如果此序列中任意两个连续数字之间的差值为-1或1且其第一个元素为0,则整数序列为单序列。
更准确地说:a1,a2,...,a是一个单序列,如果:
For any k (1 ≤ k < n): |a[k] - a[k+1]|=1,
a[1]=0
给出n和s─一个中所有元素的总和。 W需要用给定的参数构造一个序列。
如果n = 8且s = 4,则其中一个序列为[0 1 2 1 0 -1 0 1]。
注意,对于给定的n和s,我们不能形成这样的序列,我们也需要告诉它不可能。否则我们需要告诉任何这样的序列。如何解决这个问题请帮忙。
答案 0 :(得分:3)
首先,要确定是否可以解决,可以事先做好。由于你在每一步中都是+1或-1,你将从偶数,奇数,偶数到奇数......所以对于 n 的奇数值你只会是能够达到偶数,并且对于 n 的偶数值,您将只能达到奇数。可到达的范围也很简单:±(1 + 2 + 3 + ... + n)。
其次,如果您在每个步骤中绘制关于是向上(+1)还是向下(-1)的“决策树”,并在每个节点中绘制累计总和,您将看到您可以执行一种二进制搜索,用于在树中的一个叶子上找到总和。
如果您即将下冲,则转为+1,如果您即将超调则转为-1。棘手的部分是弄清楚你是否会出现下冲/过冲。你当前的“状态”应该由
计算“我到目前为止所拥有的内容”+“我可以免费获得这个级别的剩余数据”。
您在“此级别”免费获得的内容为stepsLeft * previousValue
。
这是一些伪代码。
solve(stepsLeft, prev, acc) {
if stepsLeft == 0, return empty list // base case
ifIStayHere = acc + prev*stepsLeft
step = ifIstayHere > s ? prev-1 : prev+1
return [step] concatenated by solve(stepsLeft-1, step, acc+step)
}
请注意,此解决方案不包含初始值0,因此请使用stepsLeft = n-1
调用它。
正如你所看到的,它是θ(n),它适用于我测试过的所有情况。 (在Java中实现。)
答案 1 :(得分:3)
这是对aioobe算法的另一种看法,正式证明了正确性。
给定序列a(k),定义差序列d(k)= a(k + 1) - a(k)并观察a(1)+ a(2)+ ... + a( n)=(n-1)d(1)+(n-2)d(2)+ ... + 1d(n-1)。
参数n和s的定理:,当且仅当(1)n(n-1)/ 2 mod 2 = s mod时,存在长度为n的单序列与s的求和2和(2)| s | ≤n(n-1)/ 2。
证明:通过感应n。基本情况,n = 1,是微不足道的。归纳地,由于d(k)∈{±1},我们观察到(1)和(2)都是必要条件,因为n-1 + n-2 + ... + 1 = n(n-1)/ 2和-1 mod 2 = 1 mod 2.相反,假设(1)和(2)。如果s≥0,则构造一个长度 - (n-1)序列,总和为s - (n-1)。如果s&lt;然后,构建长度 - (n-1)序列,总和为s +(n-1)。 (1)和(2)都满足这些结构(省略了一些繁琐的案例分析),因此从归纳假设得出它们成功。根据s≥0/ s <1,将该序列的元素增加/减少1。 0并在开头放0。
由于定理的证明是建设性的,我们可以用Python实现它。
def oneseq(n, s):
assert isinstance(n, int)
assert isinstance(s, int)
nchoose2 = n*(n-1)//2
abss = abs(s)
if n < 1 or abss%2 != nchoose2%2 or abss > nchoose2: return None
a = [0]
for k in range(n-1, 0, -1): # n-1, n-2, ..., 1
d = 1 if s >= 0 else -1
a.append(a[-1] + d) # a[-1] equivalent to a[len(a) - 1]
s -= k*d
return a