diff --git a/algorithm-exercises-java/src/main/java/ae/hackerrank/interview_preparation_kit/greedy_algorithms/LuckBalance.java b/algorithm-exercises-java/src/main/java/ae/hackerrank/interview_preparation_kit/greedy_algorithms/LuckBalance.java new file mode 100644 index 0000000..4017e32 --- /dev/null +++ b/algorithm-exercises-java/src/main/java/ae/hackerrank/interview_preparation_kit/greedy_algorithms/LuckBalance.java @@ -0,0 +1,81 @@ +package ae.hackerrank.interview_preparation_kit.greedy_algorithms; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * LuckBalance. + * + * @link Problem definition [[docs/hackerrank/interview_preparation_kit/greedy_algorithms/luck-balance.md]] + */ +public class LuckBalance { + + private class Competition { + private int luck; + private int important; + + Competition(int luck, int important) { + this.luck = luck; + this.important = important; + } + + public int getLuck() { + return this.luck; + } + + public int getImportant() { + return this.important; + } + } + + private LuckBalance() { } + + /** + * luckBalance. + * + * @link https://www.baeldung.com/java-sort-collection-multiple-fields#use-comparatorcomparing-and-lambda-expression + */ + public static int luckBalance(int k, List> contests) { + List importantCompetitions = new ArrayList<>(); + List nonimportantCompetitions = new ArrayList<>(); + + for (var x : contests) { + Integer luck = x.get(0); + Integer important = x.get(1); + + if (important == 1) { + importantCompetitions.add(new LuckBalance().new Competition(luck, important)); + } else { + nonimportantCompetitions.add(new LuckBalance().new Competition(luck, important)); + } + } + + importantCompetitions = importantCompetitions + .stream() + .sorted( + Comparator + .comparing(Competition::getImportant).reversed() + .thenComparing(Competition::getLuck).reversed() + ) + .collect(Collectors.toList()); + + int total = 0; + int size = importantCompetitions.size(); + + for (int i = 0; i < Math.min(k, size); i++) { + total += importantCompetitions.get(i).getLuck(); + } + + for (int i = Math.min(k, size); i < size; i++) { + total -= importantCompetitions.get(i).getLuck(); + } + + for (Competition x : nonimportantCompetitions) { + total += x.luck; + } + + return total; + } +} diff --git a/algorithm-exercises-java/src/test/java/ae/hackerrank/interview_preparation_kit/greedy_algorithms/LuckBalanceTest.java b/algorithm-exercises-java/src/test/java/ae/hackerrank/interview_preparation_kit/greedy_algorithms/LuckBalanceTest.java new file mode 100644 index 0000000..05f16e2 --- /dev/null +++ b/algorithm-exercises-java/src/test/java/ae/hackerrank/interview_preparation_kit/greedy_algorithms/LuckBalanceTest.java @@ -0,0 +1,52 @@ +package ae.hackerrank.interview_preparation_kit.greedy_algorithms; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import util.JsonLoader; + +/** + * LuckBalanceTest. +*/ +@TestInstance(Lifecycle.PER_CLASS) +class LuckBalanceTest { + public static class LuckBalanceTestCase { + public String title; + public Integer k; + public List> contests; + public Integer expected; + } + + private List testCases; + + @BeforeAll + public void setup() throws IOException { + String path = String.join("/", + "hackerrank", + "interview_preparation_kit", + "greedy_algorithms", + "luck_balance.testcases.json"); + + this.testCases = JsonLoader.loadJson(path, LuckBalanceTestCase.class); + } + + @Test void testLuckBalance() { + for (LuckBalanceTestCase test : testCases) { + Integer result = LuckBalance.luckBalance(test.k, test.contests); + + assertEquals(test.expected, result, + "%s(%d, %s) => must be: %s".formatted( + "LuckBalance.luckBalance", + test.k, + test.contests, + test.expected + ) + ); + } + } +} diff --git a/algorithm-exercises-java/src/test/resources/hackerrank/interview_preparation_kit/greedy_algorithms/luck_balance.testcases.json b/algorithm-exercises-java/src/test/resources/hackerrank/interview_preparation_kit/greedy_algorithms/luck_balance.testcases.json new file mode 100644 index 0000000..99e0243 --- /dev/null +++ b/algorithm-exercises-java/src/test/resources/hackerrank/interview_preparation_kit/greedy_algorithms/luck_balance.testcases.json @@ -0,0 +1,8 @@ +[ + { + "title": "Sample Test case 0", + "k": 3, + "contests": [[5, 1], [2, 1], [1, 1], [8, 1], [10, 0], [5, 0]], + "expected": 29 + } +] diff --git a/docs/hackerrank/interview_preparation_kit/greedy_algorithms/luck-balance.md b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/luck-balance.md new file mode 100644 index 0000000..5794a5a --- /dev/null +++ b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/luck-balance.md @@ -0,0 +1,97 @@ +# [Greedy Algorithms: Luck Balance](https://www.hackerrank.com/challenges/luck-balance) + +- Difficulty: `#easy` +- Category: `#ProblemSolvingBasic` + +Lena is preparing for an important coding competition that is preceded +by a number of sequential preliminary contests. +Initially, her luck balance is 0. +She believes in "saving luck", and wants to check her theory. +Each contest is described by two integers, `L[i]` and `T[i]`: + +- `L[i]` is the amount of luck associated with a contest. +If Lena wins the contest, her luck balance will decrease by `L[i]`; +if she loses it, her luck balance will increase by `L[i]`. + +- `T[i]` denotes the contest's importance rating. +It's equal to `1` if the contest is important, and it's equal to `0` if it's unimportant. + +If Lena loses no more than `k` important contests, what is the maximum amount +of luck she can have after competing in all the preliminary contests? +This value may be negative. + +## Example + +```text +Contest L[i] T[i] +1 5 1 +2 1 1 +3 4 0 +``` + +If Lena loses all of the contests, her will be `5 + 1 +4 = 10`. +Since she is allowed to lose important contests, +and there are only `2` important contests, +she can lose all three contests to maximize her luck at `10`. + +If `k = 1`, she has to win at least of the important contests. +She would choose to win the lowest value important contest worth `1`. +Her final luck will be `5 + 4 - 1 = 8`. + +## Function Description + +Complete the luckBalance function in the editor below. + +luckBalance has the following parameter(s): + +- `int k`: the number of important contests Lena can lose +- `int contests[n][2]`: a 2D array of integers where each `contests[i]` +contains two integers that represent the luck balance and importance of the contest + +## Returns + +- `int`: the maximum luck balance achievable + +## Input Format + +The first line contains two space-separated integers `n` and `k`, +the number of preliminary contests and the maximum number +of important contests Lena can lose. + +Each of the next lines contains two space-separated integers, +`L[i]` and `T[i]`, the contest's luck balance and its importance rating. + +## Constraints + +- $ 1 \leq n \leq 100 $ +- $ 0 \leq k \leq N $ +- $ 1 \leq L[i] \leq 10^4 $ +- $ T[i] \isin \{0,1\} $ + +## Sample Input + +```text +STDIN Function +----- -------- +6 3 n = 6, k = 3 +5 1 contests = [[5, 1], [2, 1], [1, 1], [8, 1], [10, 0], [5, 0]] +2 1 +1 1 +8 1 +10 0 +5 0 +``` + +## Sample Output + +```text +29 +``` + +## Explanation + +There are `n = 6` contests. Of these contests, `4` are important +and she cannot lose more than of them. +Lena maximizes her luck if she wins the $ 3^{rd} $ important contest +(where `L[i] = 1`) and loses all of the other five contests for a total +luck balance of `5 + 2 + 8 + 10 + 5 - 1 = 29`.