题目描述
有一些机器人分布在一条无限长的数轴上,他们初始坐标用一个下标从 0 开始的整数数组 nums 表示。当你给机器人下达命令时,它们以每秒钟一单位的速度开始移动。
给你一个字符串 s ,每个字符按顺序分别表示每个机器人移动的方向。‘L’ 表示机器人往左或者数轴的负方向移动,‘R’ 表示机器人往右或者数轴的正方向移动。
当两个机器人相撞时,它们开始沿着原本相反的方向移动。
请你返回指令重复执行 d 秒后,所有机器人之间两两距离之和。由于答案可能很大,请你将答案对 109 + 7 取余后返回。
注意:
- 对于坐标在 i 和 j 的两个机器人,(i,j) 和 (j,i) 视为相同的坐标对。也就是说,机器人视为无差别的。
- 当机器人相撞时,它们 立即改变 它们的前进方向,这个过程不消耗任何时间。
- 当两个机器人在同一时刻占据相同的位置时,就会相撞。
- 例如,如果一个机器人位于位置 0 并往右移动,另一个机器人位于位置 2 并往左移动,下一秒,它们都将占据位置 1,并改变方向。再下一秒钟后,第一个机器人位于位置 0 并往左移动,而另一个机器人位于位置 2 并往右移动。
- 例如,如果一个机器人位于位置 0 并往右移动,另一个机器人位于位置 1 并往左移动,下一秒,第一个机器人位于位置 0 并往左行驶,而另一个机器人位于位置 1 并往右移动。
做题情况
- 做出来且思路与标答一致 ☑
- 做出来但思路较为复杂
- 有思路,但时间复杂度较高无法通过
- 没有思路
自己的想法:碰撞+排序+求解两两之间的距离
第一个难点为对于碰撞的处理。在进行碰撞时,两个机器人均改变方向,有点像动能守恒中的两个小球。在动能守恒中,一个小球a静止,与小球a完全相同的小球b撞向小球a。发生碰撞之后,小球b立刻静止,小球a以与小球b相同的速度,方向运动。对于这个实例,我们可以看成小球a与小球b发生交换,或者小球b“穿过”小球a继续运动。
机器人碰撞也是同理,我们可以将碰撞看成无视空间的穿梭,即不发生碰撞,两者就像什么事都没有发生一样继续运动。
第二个难题是求解两两之间的距离。由于一个可能有10^5个小球,因此时间复杂度最高为O(nlogn)。这里我们可以用数据归纳法的思路,或者说是秦九韶乘法的思想,求每个点到前面所有点的距离,求这个距离时我们可以根据上一个点的结果来进行求解。
当然在进行求和之前我们需要将所有小球位置从小到大进行排序。
标答:
同自己的想法
实际代码
class Solution {
public:
int sumDistance(vector<int>& nums, string s, int d)
{
//由于速度都是一致的,所以正常行走是不会出现相撞的问题。
//换言之,我们不需要考虑碰撞带来的问题
int n=nums.size();
for (int i=0;i<n;++i)
{
if (s[i]=='L') nums[i]-=d;
else nums[i]+=d;
}
long long res=0;
long long last=0;
sort(nums.begin(),nums.end());
for (long long i=1;i<n;++i)
{
long long sum=(last+i*((long long)nums[i]-nums[i-1])%1000000007)%1000000007;
res=(res+sum)%1000000007;
last=sum;
}
return (int)res%1000000007;
}
};
总结
对时间复杂度的运用:
对于一个数组,我们首先看时间复杂度是如何卡的,除了卡O(n)的以外,以及数组顺序不能动的情况下,我们都可以尝试将数组进行排序。
对于这道题,d的范围取到了10^9,那么显然这个值最多是O(n)的,或者是不影响时间复杂度的。
可以通过对时间复杂度的应用来对可选的算法进行限制,可以减少很多思考量。
int与long long:
当数组量很大的时候,这个地方总是容易出错。我们需要保证所有的int值不能超,在运算的过程中同样不能超。这个比较细节,所以最好一开始就确定好把什么变量用long long表示,直接避免这样的问题。