大象起舞:用PostgreSQL解海盗分金问题_搜狐科技

原航向:大象起舞:应用PostgreSQL处理盗用成绩

作者簡介

张泽鹏(redraiment):51年长的信用卡事情架构师。。

  • 无党发掘:风控已于51出土。、信审、最重要的纪录支援差不多安心彼此的信用互插的坑。
  • 冷技术把持:51内 PostgreSQL、FreeBSD、Emacs、Lisp 技术公布员工
  • 挂空挡社会恶习有耐性的:回绝反复,寻求元自动化,自动化全自动化

交流声引见

现今午休时刷微信,牧座云和恩莫的封皮发展成了伴星共同体。,依其申述杨昌劳应用SQL来处理Oracle切中要害盗用子成绩。《学到全胜:应用SQL处理盗用归来最大值化成绩,读数后逗乐。,决议试试看。 PostgreSQL 中处理该成绩。

成绩简述

有5个海盗分为100个黄金。,定单是由一批决议的。,提升了分红突出。,超越半(适宜)可以表示保留或保存时用。,别的方式,将表现拟议使突出的海盗。。如今责任为第一体海盗赡养最好的处理突出。。

责任辨析

在原文件,本人用回溯地想来处理成绩。,但成绩的辨析对立较短。,因而我以为使牲口众多一下我的想迅速移动。。

率先,可以从在如此成绩上精炼以下有用的通知。:

  • 海盗人数:5
  • 黄金标号:100
  • 批量产物:命令曾经决议了。,海盗的标号是1-5。
  • 通信量健康状况:鼓励百分之一 > 50%
  • 最适度突出:海盗责任为科马的和黄金而打架。,前者比后者更要紧。,到这程度有三个产物。,进项一体一体地提升。

开端的的成绩授给物有海盗都是理由的。、十足有智力的,这谓语海盗们将塑炼过度。:当且仅当,适宜现行突出的得益,高于目前的突出回绝的屈服。,最适当的适宜。到这程度,为了表示保留或保存时用目前的的使突出,本人至多要行贿50%的海盗。,他们的进项高于随后的使突出。。

如此迅速移动很像总统竞选。。比方,特朗普赞成假设他能相称总统。,每一体共和国党员都可以成为一枚黄金。;希拉里成了总统。,一体黄金将发放民主党的每一体围攻。。得益很小。,但两党围攻都很变清澈。,假设过失党的主席,归来无几。,到这程度,他们将支援他们本人的党围攻。,为了学到如此仿佛无几的高进项。。

税收拆开

总而言之,为了行贿。,本人一定率先包含对手的行贿谋略。,在此基础上,它将赡养高等的的付还(海盗)、救了他的命的海盗提升了他的黄金标号。;行贿的最低消费本钱。,在竞赛SCH中可以基础的行贿最低消费进项者。

这谓语,5个海盗的最适度谋略停止4个海盗的谋略。,4个海盗的谋略停止3个海盗的谋略。,鱼贯类推。如此迅速移动,这是原文件提到的逆迅速移动。:

  • 1海盗,他有100个黄金。,就是说,分派使突出是:[100]
  • 2海盗,尽管使突出是什么。,不克不及胜任的超越先于使突出100的进项,因而其次个突出的海盗不克不及胜任的适宜无论哪个使突出。,就是说,第一体海盗一定在如此光景中落下。,分派使突出是:[零值], 100]
  • 3海盗,在最不可能的一体使突出中,一体海盗死了。,你可以用科马行贿他。,缺少黄金。,即最适度分派使突出是:[100, 0, 0]
  • 4海盗,同样地,尽管使突出是什么。,不超越100的最重要的付还。,因而海盗会反它。,剩的两名海盗缺少从先于的使突出中得益。,只需给他们1个黄金。:[98, 0, 1, 1]
  • 5海盗,后面的4个海盗可以行贿。,但粉底最低消费本钱基谐波的,第朝反方向行贿是0名海盗。,后来地从两个海盗中随机提炼物一体,他们的进项是1。,给他2个黄金。,因而有两种选择。:[97, 0, 1, 2, 0] 或 [97, 0, 1, 0, 2]

订计划者

十足迅速移动手工操作导出。,如今试着用它。 SQL 仿照迅速移动。。倒过失说 SQL 这是处理这一成绩的最适度选择。,但我以为表示保留或保存时用如此成绩来详细地检查和固化。 SQL 的知。

最重要的纪录构图

在如此成绩上,每个海盗都责任保留他的序列号和进项。。规范 SQL 假释中,除非赡养数值在远处、根本最重要的纪录典型,如字母行,它还支援复合最重要的纪录典型的装饰。,腔调是装饰。…]`。海盗的通知可以用2的概数装饰来保留。,穿着第

海盗守则,其次海盗津贴,假设海盗是死的,数额是空。。

譬如,装饰〔2〕, 海盗们编号2。、装饰〔4〕, 98说海盗4的最重要的海盗率是98枚黄金。。

分派谋略——多个海盗的通知——也可以保留,就是说,二维概数装饰。。譬如,2个海盗被分派谋略。:装饰[〔1〕, 病人, [2, 100]]`,就是说,第一体海盗曾经死了。,其次海盗有100枚黄金。。

行贿算法

粉底在上的辨析,实时行贿的移动如次。:

1。粉底每个海盗的进项来分派分派谋略。:

空是最上进的。

B)钱的标号很小。

2。上半年提升盗用

  • 半标号:驱逐本人,残余物海盗总额
    • N是偶数。:半标号为`n / 2`
    • n是陌生的的。:半标号为`(n + 1) / 2`
  • 行贿战术
    • 款项为 null 时,更顶替0
    • 款项不 null 时,加1

三。盗用的付还率为0。

本钱升序

PostgreSQL原始发生未赡养市价装饰的排序功用(intarray可插件切中要害sort有或起功能可是用于非null的一位整数装饰),要对二维整数装饰构图的分派谋略排序,本人责任率先把装饰范围到行记载(行)。,重用命令 表示保留或保存时用排序。

憎恨PostgreSQL赡养了unNEST有或起功能来将装饰形成成行,但它真正的功能是整齐的地化。,这将是一体深的的构图。。

譬如:`select UNEST(装饰)〔1〕,2],[3,4]])` 将现场恢复4行。,过失计议的2线记载。。

到这程度,责任如愿以偿装饰的一维范围有或起功能。责任应用 `array_lower(anyarray, int) 和 `array_upper(anyarray, int) 这两个有或起功能成为装饰下标RESP的上限和降谪人间。,后来地用 `generate_series` 使成为下标序列。

:SQL 装饰下标 `1` 开端。授给物谋略装饰的名称为 `strategy`,范围 排序的加密如次:

select

strategy[i][1] as id,

strategy[i][2] as amount

from

generate_series(array_lower(strategy, 1),

array_upper(strategy, 1)) as t(i)

order by

amount nulls first

穿着 `nulls first` 在炫耀中约定。 `null` 排在最前。PostgreSQL 中,`null` 默许比非 `null` 值大,因而升序在末了。,降序排列在前列。。用于加强语气 `nulls first` 或 `nulls last` 猛扣默许行动。

用垂饰安装关系

决定什么人海盗属于合伙人(上半场),一体新的下标得用垂饰安装为是你这么说的嘛!规则列表。, PostgreSQL 赡养在 `row_number()` 窗口有或起功能,可以学到目前的行的行数。;后来地应用有或起功能。 `array_length(anyarray, int) 可以成为装饰的扣押。,最不可能的一体责任行贿的海盗 `(array_length(strategy, 1) + 1) / 2`。授给物规则最重要的纪录存储器在暂时表中。 `strategies`,每个海盗的本钱加密计算如次:

select

id,

amount,

case

— 是合伙人吗?

when row_number() over () <= (array_length(strategy, 1) + 1) / 2

then 聚结(量) + 1, 0) — 活海盗长大黄金,亡故海盗复生

else 0 — 半的海盗缺少黄金。

end as cost

from

strategies

分派突出

假设行贿的本钱(总和(本钱))高于黄金总的,这谓语超越半的人不克不及成为鼓励。,保留先于的使突出。,即保留 `amount` 作为每个海盗最大的进项;别的方式,本钱更低,剩的盗用率最重要的(100) – 款项(本钱),安心海盗则将本钱替换为新朝反方向的最大付还。。

它曾经在最重要的纪录构图有些中提到过。,谋略的最重要的纪录构图是概数的二维装饰。,排序前排序,装饰已转变到行记载。,率先责任应用 PostgreSQL 的窗口有或起功能 `array_agg` 后来地将行记载替换成装饰。,同时应用 `array_cat` 添加海盗通知。

授给物上面的贴标签这样好的,同伴的最重要的纪录被存储器在 `strategies`,计算分派突出的加密如次:

select

case

when 款项(本钱) <= 100 then -- 判断是否能存活

array_cat(array_agg(array[id, 本钱,

装饰[装饰]扣押(谋略), 1) + 1,

100 – 款项(本钱)]]::int[])

else

array_cat(array_agg(array[id, 标号,

装饰[装饰]扣押(谋略), 1) + 1,

病人]::int[])

end

from

strategies

迭代

如下,分派使突出的单一苗条的功用曾经长大。:预先布置任性分派突出,它可以计算添加海盗时的最优分派谋略。。为了成为5个海盗的最适度处理突出。,你只责任反复如此有或起功能5次。;只是每回迭代的输出得是下一体输出。。SQL合理的赡养。 `with recursive`,同时充分发挥潜在的能力迭代和管道两个功用!

`with` 款项用于明确仅存取决于查询切中要害暂时表。,带上 `recursive` 关键词后,可表现反复查询,譬如,反复地查询有子典型。。我总觉得如此名字太轻易给错误的劝告了。,其十足表现迅速移动类似地以手围绕测量类似测量基础的搜索(BFS)。,譬如:

with recursive FO(n) as (

values (1), (3), (5) — 队列初始社会地位

union all

select n + 3 from foo where n < 5

)

select * from foo;

如此反复查询加密有或起功能相当于上面的迭代。 Python 加密:

(队列), FO) = ([1, 3, 5], []) # 对应 values (1), (3), (5)

while queue:

n = (0)

(n)

if n < 5: # 对应 where n < 5

queue.append(n + 3) # 对应 select n + 3

print foo # 对应 select * from foo

加密的两端都被表现。:1、3、5、4、6、7,总普通6个最重要的纪录。前三项是1。、`3`、5’是由队列设定初值的最重要的纪录。,4是由1发生的。、6’是由3使成为的、7’是由4使成为的。

发还盗用子成绩,授给物把上一节的分派谋略功用明确成一体有或起功能`bribe`,迭代加密如次:

with recursive 甜瓜(谋略) as (

values (装饰〔1〕, 100]]) — 初始社会地位,海盗填满每件东西。

union all

select

bribe(strategy) — 使成为下一体分派谋略

from

spoils

where

array_length(strategy, 1) < 5

)

就是说,当谋略的扣押没有5时,不息发生新的谋略。

使结合成为整体加密

如下,责任切中要害有功用点都是对应的。 SQL 处理突出是可以处理的。:表示保留或保存时用5次迭代,选择装饰的扣押(海盗号)到顺序的5。。上面是使结合成为整体的。 SQL 加密,在 PostgreSQL 可整齐的表现:

with recursive 甜瓜(谋略) as (

values (装饰〔1〕, 100]]) — 初始社会地位,海盗填满每件东西。

union all

select (

with strategies as ( — 用嵌套的 with 计算款项的本钱到下一体社会地位。

select

*,

case

when row_number() over () <= (array_length(strategy, 1) + 1) / 2

then 聚结(量) + 1, 0)

else 0

end as cost

from (

select

strategy[i][1] as id,

strategy[i][2] as amount

from

generate_series(array_lower(strategy, 1),

array_upper(strategy, 1)) as t(i)

order by

amount nulls first

) as t

)

select

case

when 款项(本钱) <= 100 then -- 判断是否能存活

array_cat(array_agg(array[id, 本钱,

装饰[装饰]扣押(谋略), 1) + 1,

100 – 款项(本钱)]]::int[])

else

array_cat(array_agg(array[id, 标号,

装饰[装饰]扣押(谋略), 1) + 1,

病人]::int[])

end

from

strategies

)

from

spoils

where

array_length(strategy, 1) < 5

)

select

5 + 1 – strategy[i][1] as id,

strategy[i][2] as amount

from (

select

strategy,

generate_series(array_lower(strategy, 1),

array_upper(strategy, 1)) as i

from

spoils

where

array_length(strategy, 1) = 5

) as t

order by

id;

产物如次。,功能良好。,在我的局部的试场中只责任 1ms:

新的挑动

是你这么说的嘛!突出只成为一体最优解。,从后面的辨析,本人可以牧座,5个海盗分金时有2个最优解,这样杨长者又侵袭了:你可是用简而言之吗? SQL 成为最好的处理突出?,迎将来微信交流!回到搜狐,检查更多

责任编辑:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

`