首先,你有一个数组/列表A,然后你想将它转换为给定的预期数组/列表B.您可以在数组上应用的唯一操作是InsertAt
和DeleteAt
,他们可以在列表中的某个索引处插入和删除元素。
注意:阵列B总是排序,而阵列A可能不是。
例如,您有一个[1, 4, 3, 6, 7]
,您希望它成为[2, 3, 4, 5, 6, 6, 7, 8]
这样做的一种方法是让A接受以下行动:
deleteAt(0); // which will delete element 1, arrayA now [4, 3, 6, 7]
deleteAt(0); // delete element 4 which now at index 0
// array A now [3, 6, 7]
insertAt(0, 2); // Insert value to at index 0 of array A
// array A now [2, 3, 6, 7]
insertAt(2, 4); // array now [2, 3, 4, 6, 7]
insertAt(3, 5); // array Now [2, 3, 4, 5, 6, 7]
insertAt(5, 6); // array Now [2, 3, 4, 5, 6, 6, 7]
insertAt(7, 8); // array Now [2, 3, 4, 5, 6, 6, 7, 8]
在上面的例子中,对阵列A进行了7次操作,将其转换为我们想要的数组。
因此,我们如何找到将A转换为B的步骤以及最小步骤?谢谢!
btw,删除A处所有元素的解决方案然后添加从B到A的所有内容仅适用于A& B没有任何共同点。
到目前为止我做了什么:
然而,我正在努力实施......
7
的拼写错误,现在最少的操作是7。MY THOUGHTS
部分答案 0 :(得分:2)
我有一个似乎有效的python程序,但它不是很短
__version__ = '0.2.0'
class Impossible(RuntimeError): pass
deleteAt = 'deleteAt'
insertAt = 'insertAt'
incOffset = 'incOffset'
def remove_all(size):
return [(deleteAt, i, None) for i in range(size-1, -1, -1)]
def index_not(seq, val):
for i, x in enumerate(seq):
if x != val:
return i
return len(seq)
def cnt_checked(func):
"""Helper function to check some function's contract"""
from functools import wraps
@wraps(func)
def wrapper(src, dst, maxsteps):
nsteps, steps = func(src, dst, maxsteps)
if nsteps > maxsteps:
raise RuntimeError(('cnt_checked() failed', maxsteps, nsteps))
return nsteps, steps
return wrapper
@cnt_checked
def strategy_1(src, dst, maxsteps):
# get dst's first value from src
val = dst[0]
try:
index = src.index(val)
except ValueError:
raise Impossible
# remove all items in src before val's first occurrence
left_steps = remove_all(index)
src = src[index:]
n = min(index_not(src, val), index_not(dst, val))
score = len(left_steps)
assert n > 0
left_steps.append([incOffset, n, None])
right_steps = [[incOffset, -n, None]]
nsteps, steps = rec_find_path(src[n:], dst[n:], maxsteps - score)
return (score + nsteps, (left_steps + steps + right_steps))
@cnt_checked
def strategy_2(src, dst, maxsteps):
# do not get dst's first value from src
val = dst[0]
left_steps = []
src = list(src)
for i in range(len(src)-1, -1, -1):
if src[i] == val:
left_steps.append((deleteAt, i, None))
del src[i]
n = index_not(dst, val)
right_steps = [(insertAt, 0, val) for i in range(n)]
dst = dst[n:]
score = len(left_steps) + len(right_steps)
nsteps, steps = rec_find_path(src, dst, maxsteps - score)
return (score + nsteps, (left_steps + steps + right_steps))
@cnt_checked
def rec_find_path(src, dst, maxsteps):
if maxsteps <= 0:
if (maxsteps == 0) and (src == dst):
return (0, [])
else:
raise Impossible
# if destination is empty, clear source
if not dst:
if len(src) > maxsteps:
raise Impossible
steps = remove_all(len(src))
return (len(steps), steps)
found = False
try:
nsteps_1, steps_1 = strategy_1(src, dst, maxsteps)
except Impossible:
pass
else:
found = True
maxsteps = nsteps_1 - 1
try:
nsteps_2, steps_2 = strategy_2(src, dst, maxsteps)
except Impossible:
if found:
return (nsteps_1, steps_1)
else:
raise
else:
return (nsteps_2, steps_2)
def find_path(A, B):
assert B == list(sorted(B))
maxsteps = len(A) + len(B)
nsteps, steps = rec_find_path(A, B, maxsteps)
result = []
offset = 0
for a, b, c in steps:
if a == incOffset:
offset += b
else:
result.append((a, b + offset, c))
return result
def check(start, target, ops):
"""Helper function to check correctness of solution"""
L = list(start)
for a, b, c in ops:
print(L)
if a == insertAt:
L.insert(b, c)
elif a == deleteAt:
del L[b]
else:
raise RuntimeError(('Unexpected op:', a))
print(L)
if L != target:
raise RuntimeError(('Result check failed, expected', target, 'got:', L))
start = [1, 4, 3, 6, 7]
target = [2, 3, 4, 5, 6, 6, 7, 8]
ops = find_path(start, target)
print(ops)
check(start, target, ops)
使用此代码进行一些测试后,结果显而易见 两阶段运作。第一阶段是删除项目 最初的清单,除了增加的所有项目序列之外的所有项目 目标列表(重复)。然后将缺失的项目添加到列表中 目标列表已建成。
临时结论是,如果我们找到一个算法来确定 最初出现在目标列表中的项目的最长子序列 第一个列表,按相同顺序但不一定是连续的,然后它给出最短路径。这是一个新的 而且可能更简单的问题。这可能就是你上面所说的,但从程序的输出中可以更清楚。
似乎很明显,这个问题可以归结为longest increasing subsequence
的问题答案 1 :(得分:1)
我们可以很容易地证明,如果A
中的元素集合不值得删除并且数量大于最长非元素,则问题会减少到最长的非递减子序列在A
中也减少了B
个元素中的子序列,那么此集合的所有元素必须在B
中以相同的顺序存在,这意味着它是一个更长的非递减子序列,并且与我们的断言相矛盾。此外,A
中任何不值得删除的较小集合必须以B
的顺序存在于同一顺序中,因此也是A
元素中最长的非递减子序列的一部分。 B
。
然后算法缩减为最长的子序列问题O(n log n + m)
:
(1) Find the longest non-decreasing subsequence of elements
in A that have at least the same count in B.
(2) All other items in A are to be deleted and the
missing elements from B added.