I have a below method which iterates a distance array and divide each element by a number starting with 1 and get the sum. If sum is greater than value points
which is passed to the method then start again in the for loop and divide by 2 and keep going until you find a sum which is less than value points
.
Below code works but is there any way to write this better?
public static int findMin(List<Integer> distance, int points) {
int sum = 0;
int c = 1;
while (true) {
for (Integer dist : distance) {
sum = (int) (sum + Math.ceil(dist / c));
}
if (sum <= points) {
break;
}
c++;
sum = 0;
}
return c;
}
If there is no specific reason to do Math.ceil to each ratio rather than to the final sum, you can just get the sum of all elements first and then find the value of c
sum / c <= points
sum / points <= c
if 0 < (sum / points) < 1, c = 1
else c = Math.ceil(sum / points)
public static int findMin(List<Integer> distance, int points) {
AtomicInteger c = new AtomicInteger(1);
while (distance.stream().mapToInt(d -> d / c.get()).sum() > points) c.incrementAndGet();
return c.get();
}
Correct me if I'm wrong but assuming the set of distances is [1, 2, 3]
right? Then you start with 1/1 + 2/1 + 3/1
which (let's leave them as fractions here) equals 6/1
, since they all have the same "denominator" here, it doesn't change. So that means that the first iteration, dividing by one, is literally the sum of the values. (1 + 2 + 3) / 1
divided by one. And anything divided by 1 is itself. So it's just the sum.
Now. On the second pass, if I assume correctly, 1/2 + 2/2 + 3/2
-- again leaving them as fractions -- (1 + 2 + 3) / 2
= 6/2
. By now you should see a pattern, right? First pass was 6/1
second is 6/2
next will be 6/3
...
So how about:
public static int findMin(List<Integer> distance, int points) {
int sum = 0;
for (Integer i : distance) {
sum += i;
}
int min = 1;
while (sum / min > points) {
min += 1;
}
return min;
}
Perhaps a solution like this would work?
edit So as it turns out this solution is assuming (at least partially) some mathematical accuracy, however it appears that the division per-element is required to be integer division which skews some of the results if we approach it strictly mathematically. So while not being a direct answer to the problem I feel like it's correct enough to leave here as a solution.
I think,we can do two things to improve the performance,but the method is not the best and it depend on the number of your list:
code like this
public static int findMin(List<Integer> distance, int points) {
int sum = 0;
int c = 1;
// sort the list for implement greedy algorithm
Collections.sort(distance, Comparator.reverseOrder());
while (true) {
for (Integer dist : distance) {
sum += dist / c;
// reduce the times of iterate
if (sum <= points) {
return c;
}
}
c++;
sum = 0;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.