题目: 第i层有floors[i]位住户, 他们一起坐电梯, 只能在一层停下, 请问在哪层停下所有住户爬楼梯数目和最少?
约束:
第0层没有住户
首先是笨笨的暴力扫描法, 假设电梯在第i
层, 则所有人要爬的层数为
∑
k
=
0
n
∣
k
−
i
∣
∗
f
l
o
o
r
s
[
k
]
\sum_{k=0}^n |k-i|*floors[k]
∑k=0n∣k−i∣∗floors[k]
外层循环为i
从[0,n]
遍历, 内层循环为k
从[0,n]
遍历, 时间复杂度
O
(
N
2
)
O(N^2)
O(N2), N为楼层数.
#define abs(x,y) x>y?x-y:y-x
int violentTraversal(vector<int> floors)
{
int n = floors.size();
int shortesti = 0;
int shortestSteps = INT_MAX;
for (int i = 1; i < n; i++)
{
int steps = 0;
for (int k = 0; k < n; k++)
{
steps += floors[k] * abs(k,i);
}
if (steps<shortestSteps)
{
shortestSteps = steps;
shortesti = i;
}
}
return shortesti;
}
优化:
贪心法: 从第1
层开始, 只要再往上一层需要麻烦楼下的人数<
往上一层方便的楼下的人数, 则选择此层, 因为越往上, 上层的人越少, 能方便的人越少, 已经不可能再方便更多的人了!
从第1层开始, 楼层向上递增, 直到满足以上条件则退出, 最坏情况为搜索空间穷尽, 即位于最高层时, 退出循环. 时间复杂度 O ( N ) O(N) O(N), N为楼层数.
int NFloorElevator(vector<int> floors)//第i层住户人数floors[i],认为第0层不住人
{
//初始化,位于第1层时
int i = 1;
int n = floors.size();
int N_1_i = floors[1];//第[0,i]层
//位于第[2,n]层人数和
int N_i_1_n = 0;
for (int i = 2; i < n; i++)
{
N_i_1_n += floors[i];
}
for (; i < n; i++)
{
if (i==n-1//已经到达最高层,不能再往上了!
|| N_i_1_n < N_1_i) //往上一层方便楼上的人数<往上一层麻烦的楼下的以及当前层的人数
break;
N_1_i += floors[i+1];
N_i_1_n -= floors[i+1];
}
return i;
}
简单测试:
void test(vector<int> v)
{
if (violentTraversal(v) == NFloorElevator(v))
{
cout << "正确" << endl;
}
else
{
cout << "错误" << endl;
}
}
int main()
{
test({ 0,2,3,4 });
test({ 0,5,8,3,5 });
}
效果: