您有一个整数列表,并且要为每个索引查找除该索引处的整数以外的每个整数的乘积 不能使用除法

问题描述

我目前正在研究练习面试问题。附件是我正在处理的问题的屏幕截图

enter image description here

我尝试了使用嵌套循环的暴力破解方法,目的是重构嵌套循环,但仍然无法通过暴力破解方法进行测试。

这是我尝试过的代码

def get_products_of_all_ints_except_at_index(int_list):

# Make a list with the products
products = []

for i in int_list:
    for j in int_list:
        if(i != j):
            k = int_list[i] * int_list[j]
            products.append(k)


return products

我对蛮力解决方案以及不使用嵌套循环的更有效解决方案都感到好奇。

解决方法

使用右侧和左侧累积乘积的线性算法

def productexcept(l):
    n = len(l)
    right = [1]*n
    for i in reversed(range(n-1)):
        right[i] = right[i + 1] * l[i+1]
    #print(right)
    prod = 1
    for i in range(n):
        t = l[i]
        l[i] = prod * right[i]
        prod *= t
    return l

print(productexcept([2,3,7,5]))

>> [105,70,30,42]
,

如果您被允许使用导入功能并且列表理解确实很丑陋,则可以尝试以下操作:

def merge(a,p,q,r):
    L = a[p..q]
    M = a[q..r]

    i = 0
    j = 0

    for k in range(p,r):
        if j >= len(M) or (i < len(L) and L[i] <= M[j]):
            a[k] = L[i]
            i += 1
        else:
            a[k] = M[j]
            j += 1

def merge_sort(a,r):
    if r - p > 1:
        q = p + (r - p) // 2
        merge_sort(a,q)
        merge_sort(a,r)
        merge(a,r)

        
a = [3,41,52,26,38,57,9,49]
merge_sort(a,len(a))
for _ in range(len(a)):
    print('%d',a[_])

如果不允许使用functools,则可以编写自己的函数:

from functools import reduce

l = [1,4]
[reduce(lambda x,y: x*y,[l[i] for i in range(len(l)) if i != k],1) for k,el in enumerate(l)]

我留给读者练习是将两个解决方案放入函数中。

,

我想出了这个

def product(larg):
    result = 1
    for n in larg:
        result *= n
    return result

List = [1,4]
N = len(List)
BaseList = [List[0:i] + List[i+1:N] for i in range(N)]
Products = [product(a) for a in BaseList]

print(Products)

从输入列表List中创建一个列表列表,其中每个列表中都删除了适当的整数。然后,您只需使用这些子列表的产品构建一个新列表。

,

如果要获取列表中每个元素的索引,则应尝试for i in range(len(int_list))for i in int_list实际上返回列表中的值,但不返回索引。 因此,蛮力解决方案应该是:

def get_products_of_all_ints_except_at_index(int_list):
# Make a list with the products
products = []

for i in range(len(int_list)):
    k = 1
    for j in range(len(int_list)):
        if(i != j):
            k *= int_list[j]
    products.append(k)

return products
,

以下是使用递归函数而不是循环的解决方案:

from functools import reduce


def get_products_of_all_ints_except_at_index(int_list,n=0,results=[]):
    new_list = int_list.copy()
    if n == len(int_list):
        return results
    new_list.pop(n)
    results.append(reduce((lambda x,y: x * y),new_list))
    return get_products_of_all_ints_except_at_index(int_list,n+1,results)


int_list = [1,4]
print(get_products_of_all_ints_except_at_index(int_list))
# expected results [84,12,28,21]

输出:

[84,21]
,

假设N为2的幂。

蛮力带N(N-2)个乘积。您可以通过预先计算元素对的N / 2个乘积,然后计算N / 4对的对,再计算对的对,直到剩下剩下的一对,来改善这一点。这总共需要N-2个产品。

接下来,您通过二分法将所需的部分乘积乘以形成所有所需的乘积。每个产品需要Lg(N)-1乘以,因此总共有N(Lg(N)-1)乘。

这是O(N Log N)解决方案。


N = 8的插图:

使用6个乘法,

a  b  c  d  e  f  g  h
 ab    cd    ef    gh
   abcd        efgh

然后用16个乘法,

b.cd.efgh
a.cd.efgh
ab.d.efgh
ab.c.efgh
abcd.f.gh
abcd.e.gh
abcd.ef.h
abcd.ef.g

可以从0到N-1的数字的二进制结构获得所需的表达式。

,

蛮力

您的暴力破解方法不起作用有多种原因:

(我假设至少是固定缩进)

  1. 列表索引超出范围

     for i in int_list
    

    这已经给您i,它是列表的元素,而不是索引。当i为7时,

    int_list[i]
    

    不可能了。

    循环应为for ... in range(len(int_list))

  2. 固定该结果后,结果包含太多元素。结果中有12个元素,但预期只有4个。这是由于products.append(...)处的另一个缩进问题。它需要分两个步骤进行。

  3. 固定不变,每次计算k时,大多数i*j都会被新值覆盖。要解决此问题,请在identity element处将k乘以1,然后将int_list[j]乘以它。

完整代码现在是

def get_products_of_all_ints_except_at_index(int_list):
products = []

for i in range(len(int_list)):
    k = 1
    for j in range(len(int_list)):
        if i != j:
            k *= int_list[j]
    products.append(k)

return products

优化

我首先提出“蛮力”解决方案作为答案。只要没有性能要求,就不必担心性能。那将是过早的优化。

除法的解决方案是:

def get_products_of_all_ints_except_at_index(int_list):
    products = []

    product = 1
    for i in int_list:
        product *= i

    for i in int_list:
        products.append(product//i)

    return products

因此不需要嵌套循环,并且线性Big-O时间复杂度。

一些指数技巧可以为您节省除数:只需乘以反数即可:

for i in int_list:
    products.append(int(product * i ** -1))