问题描述
统计每天不同类型金币的总数。
例如输入:
$data = [
['time'=>'2011-11-04','type'=>1,'gold'=>100],
['time'=>'2011-11-04','type'=>1,'gold'=>200],
['time'=>'2011-11-04','type'=>2,'gold'=>200],
['time'=>'2011-11-04','type'=>2,'gold'=>200]
];
输出:
[
['time'=>'2011-11-04','type'=>1,'gold'=>300],
['time'=>'2011-11-04','type'=>2,'gold'=>400]
]
说明:2011-11-04 号类型为 1 的总金币数为 100 + 200 = 300,同理 2011-11-04 号类型为 2 的总金币数为 200 + 200 = 400 。
问题分析
首先考虑什么情况下,两条记录的金币数能相加?
只有当两条记录的 'time' 和 'type' 相同时才能相加。
实现思路:
判断相邻两条记录的 'time' 和 'type' 是否相同,如果相同则更新金币总数,然后继续判断与下一条记录的 'time' 和 'type' 是否相同。重复这个过程,直到遍历了所有的记录。
参考代码
function solution($data){
$i=0;
$re = [];
while($i<count($data)){
$j = $i + 1;
$total = $data[$i]['gold'];
while($j < count($data) && $data[$i]['time'] == $data[$j]['time'] && $data[$i]['type'] == $data[$j]['type']){
$total += $data[$j]['gold'];
$j++;
}
$re[] = [$data[$i]['time'],$data[$i]['type'],$total];
$i = $j;
}
return $re;
}
时间复杂度
虽然代码中有嵌套的二层循环,但每条记录只会扫描一次,因此时间复杂度为 \(O(n)\)。
类似问题
我写完代码之后发现,这个问题的代码结构与 合并区间算法 的代码结构非常相似。
function merge($arr){
asort($arr);
$i = 0;
$merged = [];
while($i<count($arr)){
$temp = [$arr[$i][0],$arr[$i][1]];
$j = $i + 1;
while($j < count($arr) && $temp[1]>=$arr[$j][0]){
$temp[1] = max($temp[1],$arr[$j][1]);
$j++;
}
$merged[] = $temp;
$i = $j;
}
return $merged;
}
进一步抽象:
假如输入是:一个二维数组,并且子数组的某个字段的值是有一定的顺序。例如:统计每天不同类型金币的总数问题中,'time','type' 字段的值是有序的,合并区间问题中,需要先排序。
问题是合并。
解题模板:
- 先找到合并的条件。例如:在统计每天不同类型的金币总数问题中,只有当两条记录的 'time' 和 'type' 相同时才能合并金币数。
- 判断相邻两条数据能否合并,直到遍历了所有数据。
代码模板:
function solution($data){
$i=0;
$re = [];
while($i<count($data)){
$j = $i + 1;
$temp = $data[$i][...]; // 需要合并的值
while($j < count($data) && condition){
// 更新结果
...
}
$re[] = [...];//保存结果
$i = $j;
}
return $re;
}
吐槽与心得
这道题是昨天晚上的一个笔试的题目,60 分钟 7 道题,5 道选择题,SQL 语句查询和这道算法题算一道大题,最后一道是 有关 Android 的题目,后面没时间我也没仔细看。虽然题量不大,但是选择题不仅要求你选出答案,还要你解释原因。组织语言很费时间,而且考了一道 oc ,一道 Android 的选择题,我一脸懵*。后面做这道算法题的时候还有十几分钟,但是看着时间一秒一秒流逝,很慌,有一点思路又怕有问题,因为不能调试,纠结来纠结去时间就没了,还没写完就自动提交了。估计是凉了。不过今天早上花了十几分钟就解决了这个问题,感觉还是不熟练,没有解题的套路,吃一堑长一智,所以就总结了解决这类问题的模板。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。