【题目】
给定一个路径数组paths,表示一张图。paths[i] == j代表城市i连向城市j,如果paths[i] == i,则表示城市i是首都,一张图里只会有一个首都且图中除首都指向自己之外不会有环。
例如:paths={9,1,4,9,0,4,8,9,0,1} 由这个数组表示的图如下图所示。
城市1是首都所以距离为0;离首都距离为1的城市只有城市9;离首都距离为2的城市有城市0,3,7;离首都距离为3的城市有城市4,8;离首都距离为4的城市有城市2,5,6; 所以,距离为0的城市有1座;距离为1的城市有1座;距离为2的城市有3座;距离为3的城市有2座;距离为4的城市有3座;那么统计数组为numArr={1,1,3,2,3,0,0,0,0,0},numArr[i]==j代表距离为i的城市有j座; 要求实现一个void类型的函数,输入一个路径数组paths,直接在原数组上调整,使之变为numArr数组。 paths={9,1,4,9,0,4,8,9,0,1},函数处理后,paths={1,1,3,2,3,0,0,0,0,0}。
【要去】
如果paths长度为N,时间复杂度为O(N),额外空间复杂度为O(1)。
【基本思路】
分两部分来处理。第一步先将paths数组转换为距离数组,即数组中每一个位置的值表示的是该城市到首都的距离。第二步,根据距离数组计算得到统计数组。
如何得到距离数组呢?根据paths数组,我们可以得到每一个城市连向的城市,我们可以采用跳跃的方式,从一个城市一直往下一个城市跳,直到跳到首都位置,跳的次数就是该城市到首都的距离。下面以题目的例子来说明这一过程的实现:
1、从左到右遍历paths,先遍历到位置0。
paths[0] == 9,首先令paths[0] == -1(这是为了标记起跳的城市),因为城市0指向城市9,所以跳到城市9.
跳到城市9之后,paths[9] == 1,说明下一个城市是1,因为城市9是由城市0跳过来的,所以先令paths[9] = 0,然后跳向城市1。
跳到城市1之后,paths[1] == 1,说明城市1是首都。现在开始往回跳,城市1是由城市9跳过来的,所以跳回城市9。
根据之前设置的paths[9] == 0,我们知道城市9是由城市0跳过来的,在回跳之前先设置paths[9] = -1,表示城市9到首都的距离为1,之后回跳到0。
根据之前的设置paths[0] == -1,我们知道城市0是起跳位置,所以不再回跳,令paths[0] == -2,表示到首都的距离为2。
以上在跳向首都的过程中,paths数组有一个路径反指的过程,这是为了保证找到首都之后,能够完全跳回来。在跳回来的过程中,设置好这一路所跳的城市即可。
2、对于其他位置,跳跃的过程同上,但是跳跃终止的条件可以不是跳到首都,当我们跳到下一个位置发现它的值是负数,说明这个位置已经计算出了到首都的距离,我们只要在这个基础上来设置距离即可。
3、首都我们单独处理即可,找到首都的位置然后将它的值设为0,表示距离为0。
得到距离数组后,数组中的距离值都用负数表示。接下来我们根据距离数组来计算得到统计数组。该过程也是一个跳跃的过程。从左到右遍历数组,假设遍历到为i,paths[i] == -j,那么我们可以知道城市i距离首都的距离是j,先令paths[i] == 0,表示此位置不再代表距离,然后跳到位置j处,如果位置j处的值为负数-k,我们令paths[j] = 1,表示我们已经找到一个距离为j的城市(城市i)。然后根据k继续往下跳。如果位置j处的值为正数,说明该位置已经是距离为j的城市的数量统计,直接加1即可。
paths数组转成距离数组的过程中,每一个城市只经历跳出去和跳回来两个过程;距离数组转成统计数组,每一个城市只经历跳出的过程,所以整个时间复杂度是O(N)。
【代码实现】
#python3.5
def pathsToNums(paths):
def pathsToDistance(paths):
cap = -1
for i in range(len(paths)):
if paths[i] == i:
cap = i
elif paths[i] > -1:
curI = paths[i]
preI = i
paths[i] = -1
while paths[curI] != curI:
if paths[curI] > -1:
next = paths[curI]
paths[curI] = preI
preI = curI
curI = next
else:
break
value = 0 if paths[curI] == curI else paths[curI]
while paths[preI] != -1:
index = paths[preI]
paths[preI] = value - 1
value -= 1
preI = index
paths[preI] = value - 1
paths[cap] = 0
def distanceToNums(disArr):
for i in range(len(disArr)):
index = disArr[i]
if index < 0:
disArr[i] = 0
index = -index
while disArr[index] < 0:
tmp = disArr[index]
disArr[index] = 1
index = -tmp
disArr[index] += 1
disArr[0] = 1
if paths == None or len(paths) == 0:
return
pathsToDistance(paths)
distanceToNums(paths)
return paths