Skip to content

Commit 7ee43f8

Browse files
authored
Add files via upload
1 parent 66a41f9 commit 7ee43f8

File tree

1 file changed

+267
-0
lines changed

1 file changed

+267
-0
lines changed

AlgoQuestion.java

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
package com.mycompany;
2+
3+
/*
4+
Algo question:
5+
N people, M restaurants, on a one-dimensional street. All the people are to meet at one restaurant,
6+
find the restaurant, where total travel distance from all people to that restaurant is the shortest among all restaurants.
7+
8+
The problem can be solved with brutal force with O(n*m) complexity. Question is how to solve it faster than brutal force.
9+
Describe the algorithm, and why it is better than brutal force. Coding is not required
10+
11+
[zc] this is one dimensional street.
12+
13+
A list of people can be represented with their coordinates (p1, p2, ... pn).
14+
15+
A list of restaurant can be represented with their coordinates (r1, r2, ... rm)
16+
17+
The distance between i-th people and j-th restaurant can be calculated as ABS(pi - rj)
18+
19+
Time Complexity of BruteForce Algorithm 1: O(M * N)
20+
21+
Time Complexity of Proposed Algorithm 2 : O(M+N)
22+
This Algorithm tries to compute the distance in two passes of the Combined Sorted List
23+
Once from Left to Right and Another time from Right to Left
24+
Time Complexity of the Algorithm :
25+
O(M+N) : counting sort
26+
O(M+N) : Left to Right Traversal
27+
O(M+N) : Right to Left Traversal
28+
O(M) : traversal over the restautart list to find the minimal cost
29+
Overall Complexity = O(3 * (M+N) + M), removing constant multiplier and lower order terms it is O(M+N)
30+
31+
Space Complexity : Needs O(M+N) extra storage for the combine list and O(M) addtional space to store
32+
two lists of Restaurant objects for Left to Right and Right to Left Traversal respectively.
33+
34+
*/
35+
36+
import java.util.*;
37+
38+
public class AlgoQuestion {
39+
40+
public static void main(String[] args) {
41+
42+
int[] people = new int[]{1,2,4,6,7};
43+
int[] restaurants = new int[]{1,3,5};
44+
int restaurantWithShortedDist = getShortestDistanceBruteForce(people, restaurants);
45+
System.out.println("Nearest Restaurant for all people is: " + (restaurantWithShortedDist));
46+
47+
restaurantWithShortedDist = getShortestTotalDistanceOptimal(people, restaurants);
48+
System.out.println("Nearest Restaurant for all people is: " + (restaurantWithShortedDist));
49+
50+
people = new int[]{3,4,2,5,9};
51+
restaurants = new int[]{4,6,7};
52+
restaurantWithShortedDist = getShortestDistanceBruteForce(people, restaurants);
53+
System.out.println("Nearest Restaurant for all people is: " + (restaurantWithShortedDist));
54+
55+
restaurantWithShortedDist = getShortestTotalDistanceOptimal(people, restaurants);
56+
System.out.println("Nearest Restaurant for all people is: " + (restaurantWithShortedDist));
57+
58+
people = new int[]{2,6,8,10,11};
59+
restaurants = new int[]{7,9};
60+
restaurantWithShortedDist = getShortestDistanceBruteForce(people, restaurants);
61+
System.out.println("Nearest Restaurant for all people is: " + (restaurantWithShortedDist));
62+
63+
restaurantWithShortedDist = getShortestTotalDistanceOptimal(people, restaurants);
64+
System.out.println("Nearest Restaurant for all people is: " + (restaurantWithShortedDist));
65+
66+
}
67+
68+
public static int getShortestDistanceBruteForce(int[] people, int[] restaurants) {
69+
int resultRestaurant= -1;
70+
int globalMin = Integer.MAX_VALUE;
71+
int totalOperations = 0;
72+
for (int r=0; r < restaurants.length; r++) {
73+
int currentRSum = 0;
74+
for (int p=0; p < people.length; p++) {
75+
currentRSum += Math.abs(people[p] - restaurants[r]);
76+
totalOperations++;
77+
if (currentRSum > globalMin) {
78+
break;
79+
}
80+
}
81+
if (currentRSum < globalMin) {
82+
globalMin = currentRSum;
83+
resultRestaurant = r;
84+
}
85+
}
86+
System.out.println("Minimum Distance for all people: " + globalMin);
87+
return resultRestaurant;
88+
}
89+
90+
public static class Triple {
91+
//distance
92+
int d;
93+
//r == true indicates restaurant
94+
//otherwise person
95+
boolean r;
96+
int index;
97+
98+
public Triple(Integer d, Integer indx, boolean r) {
99+
this.d = d;
100+
this.r = r;
101+
this.index = indx;
102+
}
103+
public int getDistance() {
104+
return d;
105+
}
106+
}
107+
108+
public static class Restaurant {
109+
int currentCost;
110+
int cumCost;
111+
int cumPeopleCount;
112+
int peopleCount;
113+
int currentCostRight;
114+
115+
Triple r;
116+
117+
public Restaurant(Triple r) {
118+
this.r = r;
119+
}
120+
121+
//assumes setCostAndCount method already called.
122+
public void setCumCost(Restaurant prev) {
123+
//if prev is null, it means i am the first restaurant in the list
124+
if(prev == null) {
125+
cumCost = 0;
126+
cumPeopleCount = peopleCount;
127+
return;
128+
}
129+
//the cumulative cost in any direction is the cost of moving the people from a previous restaurant
130+
//to the current restaurant.
131+
//For example if we have P1, P2, R3, P4, R5
132+
//The algorithm assigns P1 and P2 to the next Restaurant R3.
133+
//P4 is assigned to R5.
134+
//Then the cumulative cost at R5 is the cost of moving P1 and P2 from R3 to R5 plus the
135+
//cost of P4 at R5.
136+
//A single pass from Left to Right cannot compute the cumulative costs of all Restaurants
137+
//against each of the people. So we perform a second pass in the opposite direction
138+
//to complete the cumulative cost computations.
139+
//Please see below for how the total cost is computed.
140+
cumCost = prev.cumCost+ prev.currentCost + Math.abs(r.d - prev.r.d) * prev.cumPeopleCount;
141+
cumPeopleCount = peopleCount + prev.cumPeopleCount;
142+
}
143+
144+
public void setCostAndCount(int c, int count) {
145+
currentCost = c;
146+
peopleCount = count;
147+
}
148+
149+
public void updateCostAndCount(int costUpdate, int countUpdate) {
150+
currentCost += costUpdate;
151+
peopleCount += countUpdate;
152+
currentCostRight = costUpdate;
153+
}
154+
}
155+
156+
//Linear implementation.
157+
public static int getShortestTotalDistanceOptimal(int[] people, int[] restaurants) {
158+
159+
int[] restaurantDistance = new int[restaurants.length];
160+
List<Restaurant> restaurantsListLR = new ArrayList<>();
161+
List<Restaurant> restaurantsListRL = new ArrayList<>();
162+
List<Triple> combined = new ArrayList<>();
163+
for (int i=0; i< people.length; i++) {
164+
combined.add(new Triple(people[i], i, false));
165+
}
166+
for (int i=0; i< restaurants.length; i++) {
167+
Triple t = new Triple(restaurants[i], i, true);
168+
combined.add(t);
169+
restaurantsListLR.add(new Restaurant(t));
170+
restaurantsListRL.add(new Restaurant(t));
171+
}
172+
173+
//TODO: do a Counting sort for people with restaurants
174+
//based on the distance from origin.
175+
//This will be O(M+N) when changed to Counting Sort
176+
combined.sort(Comparator.comparing(Triple::getDistance));
177+
178+
int runningCost = 0;
179+
int runningCount = 0;
180+
181+
Restaurant prev = null;
182+
Restaurant current = null;
183+
for (int i=0; i < combined.size(); i++) {
184+
Triple t = combined.get(i);
185+
if (t.r) {
186+
//restaurant handling
187+
current = restaurantsListLR.get(t.index);
188+
current.setCostAndCount(Math.abs((runningCount * t.d) - runningCost), runningCount);
189+
runningCost = 0;
190+
runningCount = 0;
191+
current.setCumCost(prev);
192+
prev = current;
193+
194+
} else {
195+
//people handling
196+
runningCost += t.d;
197+
runningCount++;
198+
}
199+
}
200+
201+
//if at the end of this loop we have runningCost it needs to be attributed
202+
//to current restaurant
203+
if (runningCount > 0) {
204+
current.updateCostAndCount(Math.abs((runningCount * current.r.d) - runningCost), runningCount);
205+
}
206+
207+
runningCost = 0;
208+
runningCount = 0;
209+
prev = null;
210+
current = null;
211+
212+
for (int i= combined.size() -1; i >=0; i--) {
213+
Triple t = combined.get(i);
214+
if (t.r) {
215+
//restaurant handling
216+
current = restaurantsListRL.get(t.index);
217+
current.setCostAndCount(Math.abs((runningCount * t.d) - runningCost), runningCount);
218+
runningCost = 0;
219+
runningCount = 0;
220+
current.setCumCost(prev);
221+
prev = current;
222+
223+
} else {
224+
//people handling
225+
runningCost += t.d;
226+
runningCount++;
227+
}
228+
}
229+
230+
//if at the end of this loop we have runningCost it needs to be attributed
231+
//to current restaurant
232+
if (runningCount > 0) {
233+
current.updateCostAndCount(Math.abs((runningCount * current.r.d) - runningCost), runningCount);
234+
}
235+
236+
int minCost = Integer.MAX_VALUE;
237+
int minIndex = -1;
238+
for (int i=0; i < restaurantsListLR.size(); i++) {
239+
Restaurant rL = restaurantsListLR.get(i);
240+
Restaurant rR = restaurantsListRL.get(i);
241+
int totalCost = 0;
242+
//if the restaurant is a corner restaurant we compute the total cost and try to
243+
//eliminate duplicate attribution for people who are on either sides of the first
244+
//and last restaurants
245+
//Otherwise the cost for any Middle restaurant is the cumulative cost from Left to Right
246+
//Plus the cumulative cost from Right to Left, Plus the cost of people assigned to the
247+
//Restaurant itself.
248+
249+
if (i==0) {
250+
totalCost = rL.currentCost + rR.cumCost + (rR.currentCost - rR.currentCostRight);
251+
} else if (i==restaurantsListLR.size() -1) {
252+
totalCost = (rL.currentCost - rL.currentCostRight) + rL.cumCost + rR.currentCost;
253+
} else {
254+
totalCost = rL.currentCost + rR.currentCost + rL.cumCost + rR.cumCost;
255+
}
256+
if (totalCost < minCost) {
257+
minCost = totalCost;
258+
minIndex = i;
259+
}
260+
//System.out.println("Total Cost at Restaurant:" + i + "=" + totalCost);
261+
}
262+
263+
System.out.println("Minimum Distance for all people: " + minCost);
264+
return minIndex;
265+
}
266+
267+
}

0 commit comments

Comments
 (0)