将两个排序的列表合并为一个,而无需递归

时间:2018-09-27 03:46:52

标签: python merge

我已经能够将两个排序的列表合并为一个,但是我不确定如何将它们合并到一个不递归的降序列表中。

1 个答案:

答案 0 :(得分:2)

def merge(lst1, lst2):

    if not lst1:
        return [lst2[idx] for idx in range(len(lst2)-1, -1, -1)] # lst2[::-1]
    if not lst2:
        return [lst1[idx] for idx in range(len(lst1)-1, -1, -1)] # lst1[::-1]

    merged_lst = []

    i,j = len(lst1)-1 ,len(lst2)-1 

    while i > -1 and j > -1:
        if lst1[i] > lst2[j]:
            merged_lst.append(lst1[i])
            i -=1

        elif lst1[i] < lst2[j]:
            merged_lst.append(lst2[j])
            j -=1

        else:
            merged_lst.extend( [lst1[i],lst2[j]] ) 
            i -=1
            j -=1

    if i > -1:
        merged_lst.extend( lst1[idx] for idx in range(i,-1,-1))
        # or merged_lst.extend( lst1[:i+1][::-1])
    else:
        merged_lst.extend( lst2[idx] for idx in range(j,-1,-1)) 
        # or merged_lst.extend( lst2[:j+1][::-1])

    return merged_lst

解释

辅助功能

def reverse_lst( lst):
    return [lst[idx] for idx in range(len(lst)-1, -1, -1)]


# if you don't even want to use list comprehension 
def basic_reverse_lst( lst):
    rev_lst = []

    # start( inclusive), stop( exclusive), step
    for idx in range(len(lst)-1 , -1, -1):
        rev_lst.append( lst[idx])

    return rev_lst

合并功能

def merge(lst1, lst2):
    # assuming lst1 and lst2 are sorted list(ascending order)

空列表案例(我将在后面参考)

    if not lst1:
        # since lst1 is empty our merge list will only contain elements of lst2

        return basic_reverse_lst(lst2) # if you don't want to use lst2[::-1] and list comprehension
    if not lst2:
        return reverse_lst(lst1)

merged_lst最终将由合并函数返回,它将包含我们的最终答案(降序)

    merged_lst = []


i j 分别用lst1和lst2的最后一个索引初始化,因为我们将反向遍历该列表,即从列表的最大元素到最小元素。

    # last_idx = len(lst) -1 
    i,j = len(lst1)-1 ,len(lst2)-1

了解ij的递减方式至关重要

想象两个箭头,一个指向lst1的索引i处的元素,另一个指向lst2的索引j处的元素,随着i和j的值变化,这些箭头将继续移动。

运行while循环,直到列表之一用尽为止,即直到我们没有完全遍历列表中的至少一个,这意味着一段时间后,至少一个箭头将指向索引0处的元素,并且end它将指向-1(在python中,它是列表的最后一个元素,但我们将其视为超出范围的索引,或者在这里只是表示我们已完全遍历此列表)。

    while i > -1 and j > -1:
        if lst1[i] > lst2[j]:
            merged_lst.append(lst1[i])
            i -=1

        elif lst1[i] < lst2[j]:
            merged_lst.append(lst2[j])
            j -=1

        else:
            merged_lst.extend( [lst1[i],lst2[j]] ) 

            i -=1
            j -=1

            '''
            # you can use extend( some_sequence) or do append()
            # here it depends what you want since you have not mentioned in your question exactly
            # what kind of behaviour you want when elements of two list are same I presumed that you want to add both of them in merged list

            merged_lst.append(lst1[i])
            merged_lst.append(lst2[j])
            '''

从列表中以相反的顺序提取其余元素,而我们尚未完全遍历,这与我们开始的情况相同,当传递给我们的func merge(lst1,lst2)的列表之一为空时,我们只需要要做的是反转非空列表(我们尚未完全遍历的列表)。

    if i > -1:
        # lst1 is not completely traversed yet

        # merged_lst.extend( lst1[idx] for idx in range(i,-1,-1)) or # lst1[:i+1][::-1]

        rest = lst1[:i+1] # rest contains elements of lst1 which we have not seen in while loop
        merged_lst.extend( reverse_lst(rest))

    else:
        # lst2 is not completely traversed yet
        # you can extract then reverse like we are doing in above if condition or you can simply do it in one line

        merged_lst.extend( lst2[idx] for idx in range(j,-1,-1))  # or lst2[:j+1][::-1]

    return merged_lst


print(merge([1,2,23,42],[])) # [42, 23, 2, 1]

print(merge([1,2,23,42], [5,7,11,19,21])) # [42, 23, 21, 19, 11, 7, 5, 2, 1]

print(merge([1,21,23,42], [5,7,11,19,21,97])) # [97, 42, 23, 21, 21, 19, 11, 7, 5, 1]

print(merge([1,19,19,21,21,23,42], [5,7,11,19,21,21,97])) # [97, 42, 23, 21, 21, 21, 21, 19, 19, 19, 11, 7, 5, 1]