We use cookies to ensure you have the best browsing experience on our website. Please read our cookie policy for more information about how we use cookies.
Java solution. First, remove outer, non-letter cities (will never be visited). Then, from the (new) outer letter cities, go inward until you reach an intersection city (3 or more edges) and calculate the minimum and maximum subtree value. You can consider a 'minimum' subtree is where you start or end a path at that subtree. A maximum subtree will double value of all "lines" in the subtree. Eventually, you will reach an inner city in which all subtrees are calculated. From there you can calculate an intersection's cities minimum path will add two minimum subtrees with the rest as maximum subtrees. Once you've reached the most inner intersection city, you can calculate it's minimum path and move back outerwards to calcuate the rest of the intersections minimum paths (with optimizations). One of the intersections will have the minimum path, and that's what you will return. Minimum is O(# cities), maximum is O(# cities + # edges).
staticintjeanisRoute(int[]k,int[][]roads){intbiggestCity=roads.length+1;// Trivial Casesif(biggestCity==2){returnroads[0][2];}if(biggestCity==3&&k.length==3){intsum=0;for(inti=0;i<2;i++){sum+=roads[i][2];}returnsum;}Set<Integer>letterCities=newHashSet<>();for(inti=0;i<k.length;i++){letterCities.add(k[i]);}Map<Integer,List<Integer>>adjList=newHashMap<>();Map<Edge,Integer>weights=newHashMap<>();// Create adjacency listfor(inti=1;i<=biggestCity;i++){adjList.put(i,newArrayList<>());}for(inti=0;i<roads.length;i++){int[]currRoad=roads[i];intvertex1=currRoad[0];intvertex2=currRoad[1];adjList.get(vertex1).add(vertex2);adjList.get(vertex2).add(vertex1);EdgenewEdge=newEdge(vertex1,vertex2);weights.put(newEdge,currRoad[2]);}if(biggestCity==3){intsum=0;for(inti=0;i<k.length;i++){List<Integer>connected=adjList.get(k[i]);if(connected.size()==1){intconnectedCity=connected.get(0);EdgenewEdge=newEdge(k[i],connectedCity);if(letterCities.contains(connectedCity)){returnweights.get(newEdge);}else{sum+=weights.get(newEdge);}}}returnsum;}intcitiesLeft=biggestCity;Set<Integer>outerCities=newHashSet<>();// Remove non-letter cities that will never be visited (outer of graph)// Create set of "outer cities"for(inti=1;i<=biggestCity;i++){List<Integer>connectedCities=adjList.get(i);if(connectedCities.size()!=1){continue;}if(letterCities.contains(i)){outerCities.add(i);}else{// Current City will never be visitedintcurrCity=i;while(true){intadjCity=adjList.get(currCity).get(0);adjList.get(currCity).remove(0);List<Integer>connectedToAdj=adjList.get(adjCity);for(intj=0;j<connectedToAdj.size();j++){if(connectedToAdj.get(j)==currCity){connectedToAdj.remove(j);break;}}citiesLeft--;if(adjCity>i||connectedToAdj.size()!=1){break;}if(letterCities.contains(adjCity)){outerCities.add(adjCity);break;}currCity=adjCity;}}}// For every 'intersection' can choose two subtrees to be minimum and // rest be maximum. Choose intersection that is minimal. Map<Integer,int[][]>interToMinMaxSubtrees=newHashMap<>();Map<Integer,Integer>interMaxTotal=newHashMap<>();Map<Integer,int[]>interDiffMaxMin=newHashMap<>();Map<Integer,Set<Integer>>interToVisitedEdges=newHashMap<>();Map<Integer,Integer>interNumTreesCalculated=newHashMap<>();intnoIntersection=0;Set<Integer>nextCities=newHashSet<>();// Start with Outer Cities to Intersection Citiesfor(intouter:outerCities){System.out.println("Curr Outer: "+outer);citiesLeft--;intprevCity=outer;intcurrCity=adjList.get(outer).get(0);intcurrLen=weights.get(newEdge(prevCity,currCity));while(true){List<Integer>connectedToCurr=adjList.get(currCity);intnumConnected=connectedToCurr.size();if(numConnected>2){// Found intersection city// Find edge index it currently intersected withintedgeIntersect=0;for(inti=0;i<numConnected;i++){intconnectedCity=connectedToCurr.get(i);if(connectedCity==prevCity){edgeIntersect=i;break;}}// Update mapsinterToVisitedEdges.computeIfAbsent(currCity,key->newHashSet<>()).add(edgeIntersect);int[][]minMax=interToMinMaxSubtrees.computeIfAbsent(currCity,key->newint[numConnected][2]);minMax[edgeIntersect][0]=currLen;minMax[edgeIntersect][1]=2*currLen;interMaxTotal.put(currCity,interMaxTotal.getOrDefault(currCity,0)+minMax[edgeIntersect][1]);intedgesSeen=interToVisitedEdges.get(currCity).size();interNumTreesCalculated.put(currCity,edgesSeen);interDiffMaxMin.computeIfAbsent(currCity,key->newint[2]);if(edgesSeen==numConnected-1){nextCities.add(currCity);}int[]currLargest=interDiffMaxMin.get(currCity);if(currLen<currLargest[0]){break;}if(currLen>currLargest[1]){currLargest[0]=currLargest[1];currLargest[1]=currLen;}else{currLargest[0]=currLen;}break;}// This city is part of a 'line'if(numConnected==2){citiesLeft--;intnextCity=connectedToCurr.get(0)==prevCity?connectedToCurr.get(1):connectedToCurr.get(0);currLen+=weights.get(newEdge(currCity,nextCity));prevCity=currCity;currCity=nextCity;continue;}// Went from outer city to outer city, no intersectionsnoIntersection=currLen;break;}if(noIntersection>0){returnnoIntersection;}}// Only one intersectionif(citiesLeft==1){intintersection=(int)interMaxTotal.keySet().toArray()[0];int[]largestSubTrees=interDiffMaxMin.get(intersection);intresult=interMaxTotal.get(intersection)-largestSubTrees[0]-largestSubTrees[1];returnresult;}Queue<Integer>toCalculate=newLinkedList<>();Map<Integer,int[][]>interToInterCityAndLen=newHashMap<>();inttotalMax=0;boolean[]calculated=newboolean[biggestCity];while(true){Set<Integer>newCities=newHashSet<>();for(intinter:nextCities){List<Integer>connectedToInter=adjList.get(inter);Set<Integer>edgesVisited=interToVisitedEdges.get(inter);if(edgesVisited.size()==connectedToInter.size()){continue;}intprevCity=inter;intlineStartIdx=0;intcurrCity=0;for(inti=0;i<connectedToInter.size();i++){if(!edgesVisited.contains(i)){currCity=connectedToInter.get(i);lineStartIdx=i;break;}}// If intersection to intersection already calculatedif(interToInterCityAndLen.get(inter)!=null&&interToInterCityAndLen.get(inter)[lineStartIdx][0]!=0){continue;}intcurrLen=weights.get(newEdge(prevCity,currCity));while(true){List<Integer>connectedToCurr=adjList.get(currCity);intnumConnected=connectedToCurr.size();// This city is part of a 'line'if(numConnected==2){intnextCity=connectedToCurr.get(0)==prevCity?connectedToCurr.get(1):connectedToCurr.get(0);currLen+=weights.get(newEdge(currCity,nextCity));prevCity=currCity;currCity=nextCity;continue;}// Found intersection// Find edge index that was intersectedintedgeIntersect=0;for(inti=0;i<numConnected;i++){intconnectedCity=connectedToCurr.get(i);if(connectedCity==prevCity){edgeIntersect=i;break;}}interToVisitedEdges.computeIfAbsent(currCity,key->newHashSet<>()).add(edgeIntersect);// Update intersection connectionsint[]connectCurrToInter={currCity,edgeIntersect,currLen};int[]connectInterToCurr={inter,lineStartIdx,currLen};interToInterCityAndLen.computeIfAbsent(currCity,key->newint[numConnected][3])[edgeIntersect]=connectInterToCurr;interToInterCityAndLen.computeIfAbsent(inter,key->newint[numConnected][3])[lineStartIdx]=connectCurrToInter;// Find min and max of current subtreeintpreviousMax=interMaxTotal.get(inter);intprevLargestSubTree=interDiffMaxMin.get(inter)[1];intpreviousMin=interMaxTotal.get(inter)-prevLargestSubTree;intcurrentMax=2*currLen+previousMax;intcurrentMin=previousMin+currLen;intdiffMaxMin=currentMax-currentMin;// Update mapsinterMaxTotal.put(currCity,interMaxTotal.getOrDefault(currCity,0)+currentMax);intminMax[][]=interToMinMaxSubtrees.computeIfAbsent(currCity,key->newint[numConnected][2]);minMax[edgeIntersect][0]=currentMin;minMax[edgeIntersect][1]=currentMax;interNumTreesCalculated.put(currCity,interNumTreesCalculated.getOrDefault(currCity,0)+1);interDiffMaxMin.computeIfAbsent(currCity,key->newint[2]);int[]currLargest=interDiffMaxMin.get(currCity);if(diffMaxMin>currLargest[1]){currLargest[0]=currLargest[1];currLargest[1]=diffMaxMin;}elseif(diffMaxMin>currLargest[0]){currLargest[0]=diffMaxMin;}intedgesSeen=interToVisitedEdges.get(currCity).size();if(edgesSeen==numConnected-1){newCities.add(currCity);}elseif(edgesSeen==numConnected){newCities.remove(currCity);if(interNumTreesCalculated.get(currCity)==numConnected){totalMax=interMaxTotal.get(currCity);toCalculate.add(currCity);}}break;}// while loop inner end}// for loop endif(newCities.isEmpty()){break;}nextCities=newCities;}intminSeen=Integer.MAX_VALUE;// only visit intersections where all subtrees have been calculatedwhile(!toCalculate.isEmpty()){intcurrInter=toCalculate.poll();if(calculated[currInter-1]){continue;}// Calculate minimum path for this citycalculated[currInter-1]=true;int[]currLargest=interDiffMaxMin.get(currInter);intresult=totalMax-currLargest[1]-currLargest[0];if(result<minSeen){minSeen=result;}// Calculate subtree for neighboring cityint[][]connectedToCurr=interToInterCityAndLen.get(currInter);for(inti=0;i<connectedToCurr.length;i++){intconnectedCity=connectedToCurr[i][0];if(connectedCity==0||calculated[connectedCity-1]){continue;}intnumSubTreesTotal=adjList.get(connectedCity).size();intnumSubTreesCalculated=interNumTreesCalculated.get(connectedCity);inttreesLeft=numSubTreesTotal-numSubTreesCalculated;if(treesLeft==0){continue;}// Calculate subtree from connected to currentintconnectedLen=connectedToCurr[i][2];int[][]currMaxMin=interToMinMaxSubtrees.get(currInter);intmaxRemoved=currMaxMin[i][1];intminRemoved=currMaxMin[i][0];intdiffRemoved=maxRemoved-minRemoved;intconnectedMaxSubTree=totalMax-maxRemoved+2*connectedLen;intconnectedMinSubTree;if(diffRemoved<currLargest[1]){connectedMinSubTree=connectedMaxSubTree-currLargest[1];}else{connectedMinSubTree=connectedMaxSubTree-currLargest[0];}connectedMinSubTree+=connectedLen;intconnectedDiff=connectedMaxSubTree-connectedMinSubTree;int[]largestDiffs=interDiffMaxMin.get(connectedCity);if(connectedDiff>largestDiffs[1]){largestDiffs[0]=largestDiffs[1];largestDiffs[1]=connectedDiff;}elseif(connectedDiff>largestDiffs[0]){largestDiffs[0]=connectedDiff;}// This city will never be the minimumif(largestDiffs[1]+largestDiffs[0]<=currLargest[1]+currLargest[0]){continue;}// Update maps for connectedinterNumTreesCalculated.put(connectedCity,++numSubTreesCalculated);if(--treesLeft==0){toCalculate.add(connectedCity);}intsubTreeIdx=connectedToCurr[i][1];int[][]connectedMinMax=interToMinMaxSubtrees.get(connectedCity);connectedMinMax[subTreeIdx][0]=connectedMinSubTree;connectedMinMax[subTreeIdx][1]=connectedMaxSubTree;}}returnminSeen;}
Cookie support is required to access HackerRank
Seems like cookies are disabled on this browser, please enable them to open this website
Jeanie's Route
You are viewing a single comment's thread. Return to all comments →
Java solution. First, remove outer, non-letter cities (will never be visited). Then, from the (new) outer letter cities, go inward until you reach an intersection city (3 or more edges) and calculate the minimum and maximum subtree value. You can consider a 'minimum' subtree is where you start or end a path at that subtree. A maximum subtree will double value of all "lines" in the subtree. Eventually, you will reach an inner city in which all subtrees are calculated. From there you can calculate an intersection's cities minimum path will add two minimum subtrees with the rest as maximum subtrees. Once you've reached the most inner intersection city, you can calculate it's minimum path and move back outerwards to calcuate the rest of the intersections minimum paths (with optimizations). One of the intersections will have the minimum path, and that's what you will return. Minimum is O(# cities), maximum is O(# cities + # edges).