题目描述
在战略游戏中,玩家往往需要发展自己的势力来触发各种新的剧情。一个势力的主要属性有三种,分别是文明等级(C),资源储备(R)以及人口数量(H)。在游戏开始时(第 0 天),三种属性的值均为 0。
随着游戏进程的进行,每一天玩家的三种属性都会对应增加,我们用一个二维数组 increase 来表示每天的增加情况。这个二维数组的每个元素是一个长度为 3 的一维数组,例如 [[1,2,1],[3,4,2]] 表示第一天三种属性分别增加 1,2,1 而第二天分别增加 3,4,2。
所有剧情的触发条件也用一个二维数组 requirements 表示。这个二维数组的每个元素是一个长度为 3 的一维数组,对于某个剧情的触发条件 c[i], r[i], h[i],如果当前 C >= c[i] 且 R >= r[i] 且 H >= h[i] ,则剧情会被触发。
根据所给信息,请计算每个剧情的触发时间,并以一个数组返回。如果某个剧情不会被触发,则该剧情对应的触发时间为 -1 。
示例 1:
输入: increase = [[2,8,4],[2,5,0],[10,9,8]] requirements = [[2,11,3],[15,10,7],[9,17,12],[8,1,14]]
输出: [2,-1,3,-1]
解释:
初始时,C = 0,R = 0,H = 0
第 1 天,C = 2,R = 8,H = 4
第 2 天,C = 4,R = 13,H = 4,此时触发剧情 0
第 3 天,C = 14,R = 22,H = 12,此时触发剧情 2
剧情 1 和 3 无法触发。
示例 2:
输入: increase = [[0,4,5],[4,8,8],[8,6,1],[10,10,0]] requirements = [[12,11,16],[20,2,6],[9,2,6],[10,18,3],[8,14,9]]
输出: [-1,4,3,3,3]
示例 3:
输入: increase = [[1,1,1]] requirements = [[0,0,0]]
输出: [0]
解题思路
一开始拿到这道题,心想这不是挺简单吗,外层一个循环用来累加increase,然后每累加一次,就在requirements里面循环找出满足条件得,事实证明,想得太天真了!中等难度得题目这么好想怎么可能,结果超时了。
看了别人大佬得解法,才觉得恍然大悟,用二分法来查找速度会更快,开始先一层循环保存increase所有可能的结果,然后遍历requirements每一个元素,在实现保存好的结果中使用二分查找。
代码1是暴力解法(超时):
class Solution(object): def onCondi(self, a, b): for i in range(len(a)): if a[i] < b[i]: return False return True def calPlus(self, a, b): for i in range(len(a)): a[i] += b[i] return a def getTriggerTime(self, increase, requirements): increase.insert(0, [0] * len(increase[0])) res = [-1] * len(requirements) cur = [0] * len(increase[0]) for i in range(len(increase)): cur = self.calPlus(cur, increase[i]) for j in range(len(requirements)): if self.onCondi(cur, requirements[j]): if res[j] == -1: res[j] = i return res S = Solution() print(S.getTriggerTime([[2,8,4],[2,5,0],[10,9,8]], [[2,11,3],[15,10,7],[9,17,12],[8,1,14]]))
代码1中getTriggerTime函数两层循环已经很恐怖了,特别是1 <= increase.length <= 10000, 1 <= requirements.length <= 100000,两层循环进行10亿次计算,必定超时
代码2是二分解法:
from copy import deepcopy class Solution(object): def calPlus(self, a, b): temp = deepcopy(a) for i in range(len(a)): temp[i] += b[i] return temp def getTriggerTime(self, increase, requirements): res = [-1] * len(requirements) forces = [[0, 0, 0]] for i in range(len(increase)): forces.append(self.calPlus(forces[-1], increase[i])) for i, requirement in enumerate(requirements): left, right = 0, len(forces) - 1 while left <= right: mid = left + (right - left) // 2 if requirement[0] <= forces[mid][0] and requirement[1] <= forces[mid][1] and requirement[2] <= forces[mid][2]: res[i] = mid right = mid - 1 else: left = mid + 1 return res S = Solution() print(S.getTriggerTime([[2,8,4],[2,5,0],[10,9,8]], [[2,11,3],[15,10,7],[9,17,12],[8,1,14]]))
代码2中第一层for循环首先保存结果,这个时间复杂度比较小,尽管后面也是二层循环(for和while),但是while里面是二分查找,节省了大量的循环时间,所以比代码1快不少