让我们无限地重复诸如abcd
的序列,产生以下数组:
abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd (...)
这就是问题:给定两个索引l和r(l< r),返回从索引l开始到r结束的子数组。
但是由于数组是圆形的,用常规数组表示它的分区会浪费内存,而是原始序列的两个子数组(前缀和后缀)(这里是abcd
)和一个数字表示分区中序列的完整重复次数足以定义分区。
以下是一个例子:
l = 5
r = 18
abcdab|cd.abcdabcd.abc|dabcdabcdabcdabcdabcdabcdabcd (...)
prefix = "cd"
sufix = "abc"
repeats = 2
当然,并非所有案例都完全符合上述方案。有时候前缀是空的,有时是后缀,有时不会是整个序列的任何重复,依此类推。实际上有一个特殊情况,当分区完全适合序列的一个重复(abcda|bc|dabcdabcd(...)
)时,它根本不能以这种方式表示,只能用一个表示字符串。
这并不是解决这个问题的唯一方法。由于它必然包括模运算,因此它隐藏了许多逐个错误。因此,我没有对包容性或排他性边界以及0索引和1索引设置任何限制。你可以使用任何使数学最简单的东西。通过简单地从一些参数中添加或减去1,任何算法都可以轻松地适用于任何这些设置。
如果你使用负面索引,可以获得奖励积分。
就我而言,这与语言无关。只需要伪代码或甚至简单的数学方程来获得一些关键值就足够了。
答案 0 :(得分:1)
模运算符是关键。从重复的字符串中读取索引a
将在未重复的字符串中的索引a % len(s)
处读取。所以例如切片s[:end % len(s)]
是后缀。
在像python这样的语言中,除非转向负无穷大而不是零(-1 % 3 == 2
和-1 // 3 == -3
而不是-1 % 3 == -1
和-1 / 3 == 0
),代码为非负指数案例将自动适用于否定指数案例。
在这个问题上需要注意两个棘手的角落案例:
切片可能完全落在字符串的相同重复内。在这种情况下,前缀/ rep-count / suffix约定没有意义。不检查此情况的代码会在前缀和后缀中添加错误的额外字符,并返回负重复计数。
slice_cyclic_string('abcd', 1, 3)
不应该返回('bcd', -1, 'abc')
,它应该回退到原始字符串结果。
切片可能落在重复边界上。朴素代码可能会在前缀或后缀中完全重复,而不是重复计数。
slice_cyclic_string('abcd', 0, 8)
应该返回('', 2, '')
,而不是('abcd', 1, '')
或('', 1, 'abcd')
或('abcd', 0, 'abcd')
与大多数涉及模数的代码一样,处理棘手的边界情况是通过在随机位置的模运算符之前和之后移位 - 然后不移位1来完成的。
这里的python代码可以做你想要的,除了它遵循end
索引的独占和索引从零开始的的python约定。 slice_cyclic_string("abcd", 5, 18)
返回('bcd', 2, 'ab')
:
def slice_cyclic_string(repeated_string, start, end):
n = len(repeated_string)
if start > end:
raise ValueError("start > end")
if start // n == end // n:
# The slice lies entirely within one repetition.
return repeated_string[start % n : end % n]
prefix = repeated_string[(start-1) % n + 1:]
suffix = repeated_string[:end % n]
reps = (end - start - len(prefix) - len(suffix)) // n
return prefix, reps, suffix
答案 1 :(得分:0)
我假设我们开始使用0进行索引,并且该子数组的星标为l+1
,如您的示例所示。而不是prefix
和sufix
我想使用s
和f
,它们是您的前缀的第一个字符的索引和重复模式中的前缀的最后一个字符。您的示例中为s=2
和f=2
。我还假设n
是重复模式的长度。
s = (l + 1) mod n
f = r mod n
repeats = (r-l -(n-s) -(n-f+1))/n