通过列表旋转找到最小绝对差总和的最快算法

如何解决通过列表旋转找到最小绝对差总和的最快算法

通过从左到右旋转2个列表,如果它们是 相同 长度。

轮播示例:

List [0,1,2,3,4,5] rotated to the left = [1,5,0]

List [0,5] rotated to the right= [5,4]

绝对差之和:

List 1 = [1,4]
List 2 = [5,6,7,8]

Sum of Abs. Diff. = |1-5| + |2-6| + |3-7| + |4-8| = 16

再一次,对于任意长度的列表和整数值,任务是通过简单地向左或向右旋转两个列表来寻找最小的和。

我对旋转和获取最小绝对差之和没有问题。我只想知道更聪明的方法,因为我的算法会检查每种可能的组合,但速度很慢。

这是我的暴力手段:

list1 = [45,21,64,33,49]
list2 = [90,12,77,52,28]
choices = []                # Put all possible sums into a list to find the minimum value.
for j in range(len(list1)):  # List1 does a full rotation
    total = 0
    for k in range(len(list1)):
        total += abs(list1[k] - list2[k])
    list1.append(list1.pop(0))
    choices.append(total)
print(min(choices))

什么是更聪明的方法?我也希望代码更短,时间更复杂。

我设法通过应用生成器来使其更快。这个想法归功于@kuriboh!但是由于我仍然对生成器实现还不熟悉,所以只想知道这是否是实现它的最佳方法,以减少我的时间复杂性,尤其是对于我的循环。 我们还能比这种配置更快吗?

list1 = [45,28]
choices = []
l = len(list1)
for j in range(l):
    total = sum([abs(int(list1[k])-int(list2[k])) for k in range(l)])
    list1.append(list1.pop(0))
    choices.append(total)
print(min(choices))

解决方法

由于Python会将负索引视为从右端开始计数,因此您可以将list1的绝对值减去({list2偏移k),其中0≤k

sum(abs(list1[i] - list2[i - k]) for i in range(len(list1)))

如果您想要所有这些值中的最小值

length = len(list1)
min(sum(abs(list1[i] - list2[i - k]) for i in range(length))
    for k in range(length))

此代码仍为O(n ^ 2),但进行推送和弹出操作的次数要少得多。

我真的想不出一种比O(n ^ 2)更快的算法。

,

我还没有解决完整的问题,但是在特殊情况下,输入值都是01(或任意两个不同的值,或O(1)中的任意一个值,但是我们还需要进一步的思路才能实现),我们可以通过应用快速卷积来获得O(n log n)时间算法。

该想法是将所有绝对差之和计算为List1 * reverse(1 - List2) + (1 - List1) * reverse(List2),其中1 - List表示逐点执行该操作,而*表示循环卷积(可在时间{{1 }}(使用一对FFT)。圆形卷积的定义是

O(n log n)

n-1 __ \ (f * g)(i) = /_ f(j) g((i - j) mod n). j=0 替换为List1,将f替换为reverse(1 - List2),我们得到

g

当且仅当 n-1 __ \ (List1 * reverse(1 - List2))(i) = /_ List1(j) (1 - List2((n-1-(i-j)) mod n)) j=0 n-1 __ \ = /_ List1(j) (1 - List2((j-(i+1)) mod n)). j=0 List1(j) (1 - List2((j-(i+1)) mod n))时,乘积1List1(j) = 1,否则为List2((j-(i+1)) mod n) = 0。因此,卷积的0值计算i具有List1偏移1i+1具有{{ 1}}。其他卷积计数与List2个对应的0个。鉴于我们的输入限制,这是绝对差异的总和。

代码:

0
,

带有David Eisenstat's solution的基准和我提供的两个NumPy解决方案。

500个随机整数0或1:

  189.62414 ms  slow_min_sum_abs_diff          # Like Frank's
   49.75403 ms  less_slow_min_sum_abs_diff     # My NumPy
   10.13092 ms  lesser_slow_min_sum_abs_diff   # My Numpy
    0.85030 ms  min_sum_abs_diff               # David's
    0.27434 ms  array_conversion               # for comparison

1000个随机整数0或1:

  857.02381 ms  slow_min_sum_abs_diff
  100.26820 ms  less_slow_min_sum_abs_diff
   28.55692 ms  lesser_slow_min_sum_abs_diff
    1.67077 ms  min_sum_abs_diff
    0.49301 ms  array_conversion
从-10 6 到10 6

1000个随机整数(没有戴维的整数,因为不是这样做的,会产生错误的结果):

  829.18451 ms  slow_min_sum_abs_diff
   89.97418 ms  less_slow_min_sum_abs_diff
   22.69516 ms  lesser_slow_min_sum_abs_diff

我不了解David的解决方案,但是他自己的验证令人信服,我自己做了一些工作,将每个较快的解决方案与下一个较慢的解决方案进行了比较(这就是为什么我编写了NumPy解决方案,因此我可以使用较大的输入):

passed: less_slow_min_sum_abs_diff (220 tests with n=100)
passed: lesser_slow_min_sum_abs_diff (89 tests with n=300)
passed: min_sum_abs_diff (146 tests with n=1000)
passed: min_sum_abs_diff (5 tests with n=10000)

在repl上完成的基准测试。它是Python 3.8.2 64位。

代码:

import numpy
from timeit import repeat,default_timer as timer


def array_conversion(a1,a2):
    a1 = numpy.array(a1)
    a2 = numpy.array(a2)


def convolve_circularly(a1,a2):
    return numpy.round(numpy.abs(numpy.fft.ifft(numpy.fft.fft(a1) * numpy.fft.fft(a2))))


def min_sum_abs_diff(a1,a2):
    a1 = numpy.array(a1)
    a2 = numpy.array(a2)[::-1]
    return numpy.min(convolve_circularly(a1,1 - a2) + convolve_circularly(1 - a1,a2))


def slow_min_sum_abs_diff(a1,a2):
    return min(
        sum(abs(a1[i] - a2[i - k]) for i in range(len(a1))) for k in range(len(a2))
    )


def less_slow_min_sum_abs_diff(a1,a2):
    a1 = numpy.array(a1)
    a2 = numpy.array(a2)
    return min(
        numpy.abs(a1 - numpy.roll(a2,k)).sum()
        for k in range(len(a2))
    )


def lesser_slow_min_sum_abs_diff(a1,a2):
    n = len(a2)
    a1 = numpy.array(a1)
    a2 = numpy.concatenate((a2,a2))
    return min(
        numpy.abs(a1 - a2[k:k+n]).sum()
        for k in range(n)
    )


def random_arrays(n):
    a1 = numpy.random.randint(2,size=n).tolist()
    a2 = numpy.random.randint(2,size=n).tolist()
    return a1,a2


def verify(candidate,reference,n,timelimit=1):
    t0 = timer()
    count = 0
    while timer() - t0 < timelimit:
        a1_orig,a2_orig = random_arrays(n)
        a1,a2 = a1_orig.copy(),a2_orig.copy()
        expect = reference(a1,a2)
        assert a1 == a1_orig and a2 == a2_orig
        result = candidate(a1,a2)
        assert a1 == a1_orig and a2 == a2_orig
        if result != expect:
            print('wrong:')
            print('  expected',expect,'by',reference.__name__)
            print('  got',result,candidate.__name__)
            print('  a1:',a1)
            print('  a2:',a2)
            break
        count += 1
    else:
        print('passed:',candidate.__name__,f'({count} tests with {n=})')


def main():
    if 1:
        verify(less_slow_min_sum_abs_diff,slow_min_sum_abs_diff,100)
        verify(lesser_slow_min_sum_abs_diff,less_slow_min_sum_abs_diff,300)
        verify(min_sum_abs_diff,lesser_slow_min_sum_abs_diff,1000)
        verify(min_sum_abs_diff,10000)
        print()

    funcs = [
        (10,slow_min_sum_abs_diff),(100,less_slow_min_sum_abs_diff),lesser_slow_min_sum_abs_diff),(1000,min_sum_abs_diff),array_conversion),]

    a1,a2 = random_arrays(1000)

    for _ in range(3):
        for number,func in funcs:
            t = min(repeat(lambda: func(a1,a2),number=number)) / number
            print('%11.5f ms ' % (t * 1e3),func.__name__)
        print()


if __name__ == "__main__":
    main()
    print('done')

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res