- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
序言:
这道题不是学习PHP,也不是我打算在生产环境中使用的代码。我只想看到并学习更好的方法来完成这项工作,就像我在我的方法中所做的那样。因此,请仅更正我的代码或向我展示更好、更快或更短的解决方案。问题本身已经解决了。谢谢!
问题:
几天前一个用户asked a question在这里。他的问题引起了我的注意,因为我想找到一种方法来解决他的需求。
他想获得 PHP array
的所有可能的键组合,其中值的总和为100,或尽可能接近100。他给了我们一个示例数组,我也将在我的示例中使用它:
$array = array(25, 30, 50, 15, 20, 30);
例如,一个结果应该是[2, 4, 5]
,因为 50 + 20 + 30
是100
.
$sum = $array[2] + $array[4] + $array[5]; // = 100
我觉得基本思路应该很清楚了。现在让我们来看看我的工作......
我的方法:
所以这个问题引起了我作为开发者的注意。起初,我认为这会很简单。只需做一些加法并检查结果。但后来我注意到有几点需要牢记......
有很多组合可供测试。对于示例数组,将有多达 720 ( 6! = 1*2*3*4*5*6 = 720
) 种可能的排列。为了获得所有可能的组合,我想先获得数组的所有可能排列。
但这只是事实的一半。因为数组中可能有 double 值(在您的示例中为 30
),我们无法获得数组值的所有可能排列,我们必须获得数组键的所有可能排列相反。
所以我使用了 pc_permut
php cookbook 的功能并根据我的需要修改它。它将返回键数组中所有可能的排列。
/**
* gets all possible permutations of $array
* @param array $array
* @param array $permutations
* @return array
*/
function permutations($array, $permutations = array()) {
if( !empty($array) ) {
$result = array();
for( $i = count($array) - 1; $i >= 0; --$i ) {
$newItems = $array;
$newPerms = $permutations;
list($values) = array_splice($newItems, $i, 1);
array_unshift($newPerms, $values);
$result = array_merge($result, permutations($newItems, $newPerms));
}
}
else {
$result = array($permutations);
}
return $result;
}
此函数的结果是一个多维数组,包含有序键数组中的所有排列。
Array (
[0] => Array (
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)
[1] => Array (
[0] => 1
[1] => 0
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)
[...
)
所以,现在我可以使用所有排列。可能组合的计算一点也不难。我将循环遍历排列,增加总和直到它们达到 100
或以上并返回组合键。
但是我发现我漏掉了一件事。当我得到所有可能的排列时,列表中甚至有一些结果翻了一番。解释一下,这两个结果基本一样:
[2, 4, 5]; // 50 + 20 + 30 = 100
[4, 5, 2]; // 20 + 30 + 50 = 100
我最终在计算后对键进行排序,并将它们用作结果数组中的索引。所以可以肯定的是,每个组合在结果中只存在一次。这是我的combinations
功能:
/**
* gets all possible key combinations of $array with a sum below or equal $maxSum
* @param array $array
* @param integer $maxSum
* @return array
*/
function combinations($array, $maxSum) {
// get all permutations of the array keys
$permutations = permutations(array_keys($array));
$combinations = array();
// loop all permutations
foreach( $permutations as $keys ) {
// create a container for each permutation to store calculation
$current = array(
"sum" => 0,
"keys" => array()
);
// now loop through the permutation keys
foreach( $keys as $key ) {
// if the addition is still between or equal $maxSum
if( $current["sum"] + $array[$key] <= $maxSum ) {
// increment the sum and add key to result
$current["sum"] += $array[$key];
$current["keys"][] = $key;
}
}
// to be sure each combination only exists once in the result
// order the keys and use them as array index
sort($current["keys"]);
$combinations[join("", $current["keys"])] = $current;
}
// remove the created key-index from array when finished
return array_values($combinations);
}
执行简单直接:
$array = array(25, 30, 50, 15, 20, 30);
print_r(combinations($array, 100));
结果是一个数组,包含所有组合。对于我们的示例数组,有十一种可能的组合。结果如下所示:
Array (
[0] => Array (
[sum] => 90
[keys] => Array (
[0] => 0
[1] => 1
[2] => 3
[3] => 4
)
)
[1] => Array (
[sum] => 90
[keys] => Array (
[0] => 0
[1] => 2
[2] => 3
)
)
[...
自从我将此脚本编写为 answer of the original question ,我会问自己,是否有另一种更好的方法来完成这项工作。也许有一种没有排列的方法,或者有一种方法可以从计算或结果数组中排除相同的组合。我知道我可以直接在 permutations
中执行计算功能,但这基本上是相同的工作流程。
我真的很想从你那里得到一些建议、技巧或改进。我认为这里有一些改进脚本的潜力,但实际上我不知道如何改进。但我相信它可以做得更简单直接......
感谢您的宝贵时间! :)
最佳答案
对数组进行排序会导致一些可能性:这是我正在考虑的一种:
我表示 a(selectedIndexes) 由 selectedIndexes 的所有元素组成的元素,例如a({25, 30, 30}) = (25, 30, 30)
P(n) 是索引 1 到 n 的所有组合的集合,为了清楚起见,我的数组从索引 1 开始(因此 P(2)={1, 2, (1, 2)})
我正在使用下面伪代码中解释的 2 个中断条件。第一个是 aSorted 的第一个元素 = 允许的总和。第二个是总和与排序后的第一个元素相比太小
selectedIndexes = {}
sum = 100
aSorted = {15, 20, 25, 30, 30, 50} //starting values for the example
//to clarify the following function
aSum = {15, 35, 60, 90}
function n(aSorted, sum, selectedIndexes){
compute aSum //precisely search in aSum for the index at which
//the elements are bigger than sum, and cut
answer = (P(count(aSum))) X a(selectedIndexes) // with X being the cartesian product
for (i=count(aSum)+1; i<=count(aSorted); i++){
newASorted = splice(aSorted, count(aSum))
// 1st break condition
if(newASorted is empty) return answer
// 2nd break condition the new sum < the first element of aSorted
if (aSorted(i)<sum && sum-aSorted(i)>=aSorted(1)){
answer += n(newASorted, sum-aSorted(i), push(selectedIndexes,
i))
}
}
return answer
}
关于数组中元素的数量,这个算法的复杂度感觉是二次方的(快速检查后它更像是 n^log2(n) 阶)
为了让它不那么抽象,让我们开发这个例子(警告我更相信这个例子而不是伪代码,尽管我自己在伪代码中没有看到不准确之处):
n({15, 20, 25, 30, 30, 50}, 100, {}) = P(4) + n({15, 20, 25, 30, 30}, 50, {6}) + n({15, 20, 25, 30}, 70, {5})
从开发等式右边的第一个 n 函数开始
n({15, 20, 25, 30, 30}, 50, {5}) = (P(2) X {6}) + n({15, 20, 25, 30}, 20, { 5, 6}) + n({15, 20, 25}, 20, {4, 6}) + n({15, 20}, 25, {3, 6})
n({15, 20, 25, 30}, 20, {5, 6}) = (P(1) X {(5, 6)})//+ n({15}, 0, { 2, 5, 6}) (but 0<15) 中断条件 2
n({15, 20, 25}, 20, {4, 6}) = P(1) X {(4, 6)}//并打破条件 2
n({15, 20}, 25, {3, 6}) = P(1) X {(3, 6)}//+ n({15}, 5, {2, 3, 6} ) (but 5<15) 打破条件 2
现在开发方程右边的第二个n函数
n({15, 20, 25, 30}, 70, {5}) = (P(3) X {5}) + n({15, 20, 25}, 40, {4, 5} )
n({15, 20, 25}, 40, {4, 5}) = (P(2) X {(4, 5)}) + n({15, 20}, 15, {3, 4, 5})
n({15, 20}, 15, {3, 4, 5}) = P(1) x {(3, 4, 5)}//+ n({}, 0, {1, 3 , 4, 5}) 新的中断条件aSum为空
关于php - 计算 php 数组 : How to improve my Algorithm? 内可能的解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38545028/
我在 JavaScript 文件中运行 PHP,例如...... var = '';). 我需要使用 JavaScript 来扫描字符串中的 PHP 定界符(打开和关闭 PHP 的 )。 我已经知道使
我希望能够做这样的事情: php --determine-oldest-supported-php-version test.php 并得到这个输出: 7.2 也就是说,php 二进制检查 test.
我正在开发一个目前不使用任何框架的大型 php 站点。我的大问题是,随着时间的推移慢慢尝试将框架融入应用程序是否可取,例如在创建的新部件和更新的旧部件中? 比如所有的页面都是直接通过url服务的,有几
下面是我的源代码,我想在同一页面顶部的另一个 php 脚本中使用位于底部 php 脚本的变量 $r1。我需要一个简单的解决方案来解决这个问题。我想在代码中存在的更新查询中使用该变量。 $name)
我正在制作一个网站,根据不同的情况进行大量 PHP 重定向。就像这样...... header("Location: somesite.com/redirectedpage.php"); 为了安全起见
我有一个旧网站,我的 php 标签从 因为短标签已经显示出安全问题,并且在未来的版本中将不被支持。 关于php - 如何避免在 php 文件中写入
我有一个用 PHP 编写的配置文件,如下所示, 所以我想用PHP开发一个接口(interface),它可以编辑文件值,如$WEBPATH , $ACCOUNTPATH和 const值(value)观
我试图制作一个登录页面来学习基本的PHP,首先我希望我的独立PHP文件存储HTML文件的输入(带有表单),但是当我按下按钮时(触发POST到PHP脚本) )我一直收到令人不愉快的错误。 我已经搜索了S
我正在寻找一种让 PHP 以一种形式打印任意数组的方法,我可以将该数组作为赋值包含在我的(测试)代码中。 print_r 产生例如: Array ( [0] => qsr-part:1285 [1]
这个问题已经有答案了: 已关闭11 年前。 Possible Duplicate: What is the max key size for an array in PHP? 正如标题所说,我想知道
我正在寻找一种让 PHP 以一种形式打印任意数组的方法,我可以将该数组作为赋值包含在我的(测试)代码中。 print_r 产生例如: Array ( [0] => qsr-part:1285 [1]
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
我在 MySQL 数据库中有一个表,其中存储餐厅在每个工作日和时段提供的菜单。 表结构如下: i_type i_name i_cost i_day i_start i_
我有两页。 test1.php 和 test2.php。 我想做的就是在 test1.php 上点击提交,并将 test2.php 显示在 div 中。这实际上工作正常,但我需要向 test2.php
我得到了这个代码。我想通过textarea更新mysql。我在textarea中回显我的MySQL,但我不知道如何更新它,我应该把所有东西都放进去吗,因为_GET模式没有给我任何东西,我也尝试_GET
首先,我是 php 的新手,所以我仍在努力学习。我在 Wordpress 上创建了一个表单,我想将值插入一个表(data_test 表,我已经管理了),然后从 data_test 表中获取所有列(id
我有以下函数可以清理用户或网址的输入: function SanitizeString($var) { $var=stripslashes($var); $va
我有一个 html 页面,它使用 php 文件查询数据库,然后让用户登录,否则拒绝访问。我遇到的问题是它只是重定向到 php 文件的 url,并且从不对发生的事情提供反馈。这是我第一次使用 html、
我有一个页面充满了指向 pdf 的链接,我想跟踪哪些链接被单击。我以为我可以做如下的事情,但遇到了问题: query($sql); if($result){
我正在使用 从外部文本文件加载 HTML/PHP 代码 $f = fopen($filename, "r"); while ($line = fgets($f, 4096)) { print $l
我是一名优秀的程序员,十分优秀!