我从2010年开始研究过去的Google Codejam算法,但时间复杂度非常糟糕。
以下是来自Google Codejam的问题:https://code.google.com/codejam/contest/619102/dashboard
TLDR - 想象一下两个塔的两侧有一条数字线,我们从一个建筑物数字线(比如从10)到另一个建筑物数字线上的另一个点(从1开始)画一条线。如果我们这样做n次,那些线会相交多少次?
我想知道这里是否有人能够提出一种方法可以加快我的算法速度? 4个小时后我真的看不到一个,我失去了我的miinnnnddd。
这是我现在的代码。
示例输入是:
2 - (案件数量)
3 - (#1中的导线数量)
1 10
5 5
7 7
案例#1:2 - (第1,10,5,5,7,7行之间的2个交叉点)
2 - (情况#2中的导线数量)
5 5
2 2
案例#2:0 - (没有线相交)
def solve(wire_ints, test_case):
answer_integer = 0
for iterI in range(number_wires):
for iterJ in range(iterI):
holder = [wire_ints[iterI], wire_ints[iterJ]]
holder.sort()
if holder[0][1] > holder[1][1]:
answer_integer = answer_integer + 1
return("Case #" + str(test_case) + ":" + " " + str(answer_integer))
for test_case in range(1, int(input()) + 1):
number_wires = int(input())
wire_ints = []
for count1 in range(number_wires):
left_port,right_port = map(int, input().split())
wire_ints.append((left_port,right_port))
answer_string = solve(wire_ints, test_case)
print(answer_string)
这个算法对我给它的任何输入都有效,但正如我所说的非常难看和慢。
帮助将不胜感激!
答案 0 :(得分:1)
由于N
为1000,因此可以接受O(N^2)
的算法。所以你要做的就是用一个端点对电线进行排序。
//sorted by first number
1 10
5 5
7 7
然后从头开始处理每一行,并检查它是否与之前的行相交。如果它之前的一条线的第二个端点大于当前线的第二个点,则它们具有交点。这需要两个循环,因此O(N^2)
复杂度足以满足N=1000
。您也可以将其解释为反转计数。你必须计算列表按第一个终点排序的第二个终点的反转次数。
10 5 7 -> number of inversions is 2, because of (10,5) and (10,7)
还有O(NlogN)
approach来计算您对此问题不需要的反转次数。