Python 给定一组数字,求其中最长算术级数的长度
我的方法如下Python 给定一组数字,求其中最长算术级数的长度,python,algorithm,Python,Algorithm,我的方法如下 1.我正在创建一个字典,用于存储所有数字对和计数之间的差异 2.键包含差异,值是一个列表。列表的第一个索引是差异的出现次数,以下索引仅表示算术级数之后的数字 我已经为此编写了以下代码 d = {} for i in range(len(A)-1): for j in range(i+1, len(A)): if A[i]-A[j] in d.keys(): d[A[i]-A[j]][0] += 1 d[A[i]
1.我正在创建一个字典,用于存储所有数字对和计数之间的差异
2.键包含差异,值是一个列表。列表的第一个索引是差异的出现次数,以下索引仅表示算术级数之后的数字 我已经为此编写了以下代码
d = {}
for i in range(len(A)-1):
for j in range(i+1, len(A)):
if A[i]-A[j] in d.keys():
d[A[i]-A[j]][0] += 1
d[A[i]-A[j]].append(A[j])
else:
d[A[i]-A[j]] = [2, A[i], A[j]]
# Get the key,value pair having the max value
k,v = max(d.items(), key=lambda k: k[1])
print(v[0])
例如,如果输入是[20,1,15,3,10,5,8]
,则我的输出是4
但是,我的代码在以下输入中失败[83,20,17,43,52,78,68,45]
预期结果是2,但我得到3。当我打印字典的内容时,我发现字典里有这样的条目
-25: [3, 20, 45, 68], -26: [3, 17, 43, 78], -35: [3, 17, 52, 78]
我不明白为什么它们会出现,因为在-25的情况下,68和45的差值不是25,我在将值添加到字典之前进行检查。
有人能指出我代码中的错误吗
我的完整输出是
{63: [2, 83, 20], 66: [2, 83, 17], 40: [2, 83, 43], 31: [2, 83, 52], 5: [2, 83, 78], 15: [2, 83, 68], 38: [2, 83, 45], 3: [2, 20, 17], -23: [2, 20, 43], -32: [2, 20, 52], -58: [2, 20, 78], -48: [2, 20, 68], -25: [3, 20, 45, 68], -26: [3, 17, 43, 78], -35: [3, 17, 52, 78], -61: [2, 17, 78], -51: [2, 17, 68], -28: [2, 17, 45], -9: [2, 43, 52], -2: [2, 43, 45], -16: [2, 52, 68], 7: [2, 52, 45], 10: [2, 78, 68], 33: [2, 78, 45], 23: [2, 68, 45]}
请注意:
d.keys()
中,但不检查数字是否存在于LPA中。e、 g:当数字是43时,68 diff是25,但您当前的列表是[2,20,45]。在这种情况下,具有相同差异25的多圈A[j]
,但没有插入A[i]
,因此您只插入了68,而不是43我认为您使用的算法无法解决您想要解决的问题。 主要问题是扩展算术序列的标准没有考虑序列本身。 例如,考虑:
A = [10, 20, 50, 60]
有两个序列属于差异-10
,因此dict
实际上不是一个好的数据结构,不适合作为算法的基础,至少不是您想要的方式
编辑 你可以用多种方法解决这个问题。 一种非常直接但效率不高的方法如下:
- 对所有元素进行排序(严格来说这不是必需的,但它会使其余元素更高效)
- 从考虑所有要素开始
- 确定是否所有元素实际上都是算术级数
- 仅计算连续元素的差值
- 如果它们都有相同的值,那么这是一个算术级数
- 如果它们是算术级数,则完成操作;如果不是,则迭代删除元素并重复上述操作,直到找到算术级数
import itertools
def is_arithmetic_progression(items):
diffs = [x - y for x, y in zip(items[1:], items[:-1])]
return diffs[1:] == diffs[:-1]
def skip_items(items, indexes):
return [item for i, item in enumerate(items) if i not in indexes]
def lap_combs(items, sorting=True):
if sorting:
items = sorted(items)
for i in range(len(items)):
for indexes in itertools.combinations(range(len(items)), i):
new_items = skip_items(items, indexes)
if is_arithmetic_progression(new_items, False):
return new_items
items = [83, 20, 17, 43, 52, 78, 68, 45]
longest_ap = lap_combs(items)
print(longest_ap)
# [78, 83]
items = [83, 20, 17, 43, 52, 78, 68, 45, 70]
longest_ap = lap_combs(items)
print(longest_ap)
# [20, 45, 70]
def seed_diff_len_to_seq(seed, diff, length):
return [seed + diff * k for k in range(length)]
def lap_diffs(items):
half_len_items = len(items) // 2
span = max(items) - min(items)
seed = 0
max_seq_len = 0
diff = None
set_items = set(items)
for item_i, item_j in itertools.combinations(sorted(items), 2):
diff_ji = item_j - item_i
if diff_ji == 0:
seq_len = sum(1 for item in items if item == item_i)
elif abs(diff_ji * max_seq_len) > span:
continue
else:
seq_len = 2
while item_i + diff_ji * seq_len in set_items:
seq_len += 1
if seq_len > max_seq_len:
max_seq_len = seq_len
seed = item_i
diff = diff_ji
if seq_len > half_len_items:
break
return seed_diff_len_to_seq(seed, diff, max_seq_len)
编辑2: 请注意,可以通过分析排序项目的差异来进一步优化:
- 计算任意两个项目之间的所有差异
- 对于给定的差异,计算项目中有多少个元素
- 跟踪给定项和元素的最大元素数
- 如果对于给定的差异,项目包含的数字不能超过最大值,则跳过该选项
- 如果元素数超过项目数的一半,则停止
import itertools
def is_arithmetic_progression(items):
diffs = [x - y for x, y in zip(items[1:], items[:-1])]
return diffs[1:] == diffs[:-1]
def skip_items(items, indexes):
return [item for i, item in enumerate(items) if i not in indexes]
def lap_combs(items, sorting=True):
if sorting:
items = sorted(items)
for i in range(len(items)):
for indexes in itertools.combinations(range(len(items)), i):
new_items = skip_items(items, indexes)
if is_arithmetic_progression(new_items, False):
return new_items
items = [83, 20, 17, 43, 52, 78, 68, 45]
longest_ap = lap_combs(items)
print(longest_ap)
# [78, 83]
items = [83, 20, 17, 43, 52, 78, 68, 45, 70]
longest_ap = lap_combs(items)
print(longest_ap)
# [20, 45, 70]
def seed_diff_len_to_seq(seed, diff, length):
return [seed + diff * k for k in range(length)]
def lap_diffs(items):
half_len_items = len(items) // 2
span = max(items) - min(items)
seed = 0
max_seq_len = 0
diff = None
set_items = set(items)
for item_i, item_j in itertools.combinations(sorted(items), 2):
diff_ji = item_j - item_i
if diff_ji == 0:
seq_len = sum(1 for item in items if item == item_i)
elif abs(diff_ji * max_seq_len) > span:
continue
else:
seq_len = 2
while item_i + diff_ji * seq_len in set_items:
seq_len += 1
if seq_len > max_seq_len:
max_seq_len = seq_len
seed = item_i
diff = diff_ji
if seq_len > half_len_items:
break
return seed_diff_len_to_seq(seed, diff, max_seq_len)
对此进行基准测试(包括as
lap\u maxprogr()
和aslap\u dict()
,而lap\u combs()
至少慢一个数量级,并且不包括在图中)表明lap\u diff()
是最快的(只要输入项的数量超过大约12个):
(全面分析)
(请注意,
lap_diff()
使用了与lap_maxprogr()
基本相同的方法,并进行了一些优化)。您必须认为,btw数字的差异不足以作为一个键,例如8-3=5,也就是5-0=5
您可以尝试:
def length_longest_AP(A):
d = {}
A.sort()
for index_i, i in enumerate(A[:-1]):
for index, j in enumerate(A[index_i + 1 :]):
dif = j - i
key = f'{i}_{index_i}_{dif}'
if key in d:
continue
d[key] = [i, j]
possible_next = j + dif
try:
current_index = index_i + 1 + index
possible_next_one_index = current_index + A[current_index + 1:].index(possible_next)
# avoiding repetitions
if current_index == possible_next_one_index:
possible_next_one_index = current_index + 1
except ValueError:
continue
while True:
d[key].append(possible_next)
possible_next += dif
try:
current_index = possible_next_one_index
possible_next_one_index = current_index + A[current_index + 1:].index(possible_next)
# avoiding repetitions
if current_index == possible_next_one_index:
possible_next_one_index = current_index + 1
except ValueError:
break
return len(max(d.values(), key=len))
print(length_longest_AP([20,1,15,3,10,5,8]))
print(length_longest_AP([1,1,1,1,1,1,1,1,1,1]))
print(length_longest_AP([83,20,17,43,52,78,68,45]))
输出:
4
10
2
另一种方法。将每一对视为一个进展的开始,并尝试扩展这一进展。 重要优化:如果一个进度包含至少一半的总项目,那么它必须是最长的潜在进度
import itertools
def maxprogr(items):
# 2 or more numbers required to find any progression
# if there are multiple maximums, the first one is returned
half = len(items) / 2
pmax = (None, None, 0)
for start, stop in itertools.combinations(sorted(items), 2):
diff = stop - start
if diff == 0:
plen = sum(1 for x in items if x == start)
else:
plen = 2
while start + diff*plen in items:
plen += 1
if plen > pmax[2]:
pmax = (start, diff, plen)
if plen > half:
break
return pmax
# and some tests:
def print_maxprogr(items):
print("MAX: start={0[0]}, diff=+{0[1]}, len={0[2]}".format(maxprogr(items)))
test1 = [20,1,15,3,10,5,8]
print_maxprogr(test1)
test2 = [83, 20, 17, 43, 52, 78, 68, 45, 70]
print_maxprogr(test2)
test3 = [83, 20, 17, 43, 52, 78, 68, 45]
print_maxprogr(test3)
test4 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
print_maxprogr(test4)
测试输出:
MAX: start=5, diff=+5, len=4
MAX: start=20, diff=+25, len=3
MAX: start=17, diff=+3, len=2
MAX: start=1, diff=+0, len=10
最大值:开始=5,差异=5,长度=4
最大值:开始=20,差异=25,长度=3
最大值:开始=17,差异=+3,长度=2
最大值:开始=1,差异=+0,长度=10
(代码在发布后1小时更新以修复一个小错误)当i=3时,您的a[i]=43,j从4到7变化。因此,在j=6时,A[j]变为68,然后差值为-25。问题在于,你的算法并不关心差异来自何处。它可以在列表中的任意两个数字之间,这不是算术级数。@JiteshMalipeddi请参见编辑2,包括基准测试