diff --git a/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist-solution-notes.md b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist-solution-notes.md new file mode 100644 index 0000000..a79054f --- /dev/null +++ b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist-solution-notes.md @@ -0,0 +1,48 @@ +# [Greedy Algorithms: Greedy Florist](https://www.hackerrank.com/challenges/greedy-florist) + +- Difficulty: `#medium` +- Category: `#ProblemSolvingBasic` + +## About the problem statement + +At first it seems a bit confusing. Due the problem statement tends to +make us believe that the most convenient thing is to start with the highest +numbers, but the examples doesn't not present a logical descending order. + +## Way of thinking + +After rereading the problem several times it can be determined that: + +- It does not matter who the buyers are, nor in what order they buy, +nor how much each one buys. +The important thing is how many people are organized +into a group to minimize the purchase price. + +- If the number of people in the group is greater than or equal to +the number of different flowers, then the price is the lowest possible, +because they can all be purchased "in a single pass", +making each person in the group (or less) buy 1 unit. + +- The price of flowers does matter, therefore it is more convenient to buy +the most expensive ones first. +Each "round" of purchasing makes the flowers more expensive, +therefore it is better to buy the cheapest ones in the last "round." + +## Deductions + +- It seems convenient to sort the flower price list entry in descending order +(or in ascending order, traversing the new sorted list in reverse). + +- The number of passes depends on how many "groups" of "k - people" +fit in the list of flowers, that is: +$ \textbf{\#(c) / k}$ (integer division) + +- At first I assumed that the order in which the traversal is done in +the examples was a suggestion of the criteria in which the list of flowers +should be traversed to reach the solution. + + Finally, realizing that the price calculation in descending order + (and "the round" in which the purchase is made) + and the example were equivalent, made me consider the idea that the order of + the examples might just be a distractor, + introduced on purpose to make deducing the solution a little more difficult. diff --git a/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist.md b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist.md new file mode 100644 index 0000000..4cbf097 --- /dev/null +++ b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist.md @@ -0,0 +1,135 @@ +# [Greedy Algorithms: Greedy Florist](https://www.hackerrank.com/challenges/greedy-florist) + +- Difficulty: `#medium` +- Category: `#ProblemSolvingBasic` + +A group of friends want to buy a bouquet of flowers. +The florist wants to maximize his number of new customers and the money he makes. +To do this, he decides he'll multiply the price of each flower by the number +of that customer's previously purchased flowers plus `1`. +The first flower will be original price, $(0 + 1) \times \text{original price}$, +the next will be $(1 + 1) \times \text{original price}$ and so on. + +Given the size of the group of friends, the number of flowers they want +to purchase and the original prices of the flowers, determine the minimum cost +to purchase all of the flowers. +The number of flowers they want equals the length of the array. + +## Example + +`c = [1, 2, 3, 4]` +`k = 3` + +The length of `c = 4`, so they want to buy `4` flowers total. +Each will buy one of the flowers priced `[2, 3, 4]` at the original price. +Having each purchased `x = 1` flower, +the first flower in the list, `c[0]`, will now cost +$ ( + \textsf{\textbf{current purchase}} + + + \textsf{\textbf{previous purchase}} +) \times +\textsf{\textbf{c[0]}} $. +The total cost is `2 + 3 + 4 + 2 = 11`. + +## Function Description + +Complete the getMinimumCost function in the editor below. + +getMinimumCost has the following parameter(s): + +- `int c[n]`: the original price of each flower +- `int k`: the number of friends + +## Returns + +- `int`: the minimum cost to purchase all flowers + +## Input Format + +The first line contains two space-separated integers `n` and `k`, +the number of flowers and the number of friends. +The second line contains `n` space-separated positive integers `c[i]`, +the original price of each flower. + +## Constraints + +- $ 1 \leq n, k \leq 100 $ +- $ 1 \leq c[i] \leq 10^5 $ +- $ answer < 2^31 $ +- $ 0 \leq i \leq n $ + +## Sample Input 0 + +```text +3 3 +2 5 6 +``` + +## Sample Output 0 + +```text +13 +``` + +## Explanation 0 + +There are `n = 3` flowers with costs `c = [2, 5, ,6]` and `k = 3` people in the group. +If each person buys one flower, +the total cost of prices paid is `2 + 5 + 6 = 13` dollars. +Thus, we print `13` as our answer. + +## Sample Input 1 + +```text +3 2 +2 5 6 +``` + +## Sample Output 1 + +```text +15 +``` + +## Explanation 1 + +There are `n = 3` flowers with costs `c = [2, 5, 6]` and `k = 2` +people in the group. +We can minimize the total purchase cost like so: + +1. The first person purchases 2 flowers in order of decreasing price; +this means they buy the more expensive flower ($ c_1 = 5 $) first at price +$ + p_1 = (0 + 1) \times 5 = 5 +$ +dollars and the less expensive flower ($ c_0 = 5 $) second at price +$ + p_0 = (1 + 1) \times 2 = 4 +$ + dollars. +2. The second person buys the most expensive flower at price +$ + p_2 = (0 + 1) \times 6 = 6 +$ +dollars. + +We then print the sum of these purchases, which is `5 + 4 + 6 = 15`, as our answer. + +## Sample Input 2 + +```text +5 3 +1 3 5 7 9 +``` + +## Sample Output 2 + +```text +29 +``` + +## Explanation 2 + +The friends buy flowers for `9, 7`, and `3, 5`, and `1` for a cost of +`9 + 7 + 3 * (1 + 1) + 5 + 1 * (1 + 1) = 29`. diff --git a/src/algorithm_exercises_csharp/hackerrank/interview_preparation_kit/greedy_algorithms/GreedyFlorist.cs b/src/algorithm_exercises_csharp/hackerrank/interview_preparation_kit/greedy_algorithms/GreedyFlorist.cs new file mode 100644 index 0000000..d7eb5ce --- /dev/null +++ b/src/algorithm_exercises_csharp/hackerrank/interview_preparation_kit/greedy_algorithms/GreedyFlorist.cs @@ -0,0 +1,38 @@ +// @link Problem definition [[docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist.md]] +// @link Solution notes [[docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist-solution-notes.md]] + +namespace algorithm_exercises_csharp.hackerrank.interview_preparation_kit.greedy_algorithms; + +using System.Diagnostics.CodeAnalysis; + + +/** + * GreedyFlorist. + * + */ +public static class GreedyFlorist +{ + /** + * getMinimumCost. + */ + + public static int getMinimumCost(int k, int[] c) + { + List flowers = new List(c); + flowers.Sort(); + flowers.Reverse(); + + int totalCost = 0; + int i = 0; + + foreach (var flowerCost in flowers) + { + int position = i / k; + totalCost += (position + 1) * flowerCost; + + i += 1; + } + + return totalCost; + } +} diff --git a/src/algorithm_exercises_csharp_test/Resources/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.testcases.json b/src/algorithm_exercises_csharp_test/Resources/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.testcases.json new file mode 100644 index 0000000..50cac1c --- /dev/null +++ b/src/algorithm_exercises_csharp_test/Resources/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.testcases.json @@ -0,0 +1,33 @@ +[ + { + "title": "Sample Test case 0", + "k": 3, + "c": [2, 5, 6], + "expected": 13 + }, + { + "title": "Sample Test case 1", + "k": 2, + "c": [2, 5, 6], + "expected": 15 + }, + { + "title": "Sample Test case 2", + "k": 3, + "c": [1, 3, 5, 7, 9], + "expected": 29 + }, + { + "title": "Test case 1", + "k": 3, + "c": [ + 390225, 426456, 688267, 800389, 990107, 439248, 240638, 15991, 874479, + 568754, 729927, 980985, 132244, 488186, 5037, 721765, 251885, 28458, + 23710, 281490, 30935, 897665, 768945, 337228, 533277, 959855, 927447, + 941485, 24242, 684459, 312855, 716170, 512600, 608266, 779912, 950103, + 211756, 665028, 642996, 262173, 789020, 932421, 390745, 433434, 350262, + 463568, 668809, 305781, 815771, 550800 + ], + "expected": 163578911 + } +] diff --git a/src/algorithm_exercises_csharp_test/hackerrank/interview_preparation_kit/greedy_algorithms/GreedyFloristTest.cs b/src/algorithm_exercises_csharp_test/hackerrank/interview_preparation_kit/greedy_algorithms/GreedyFloristTest.cs new file mode 100644 index 0000000..08f83e2 --- /dev/null +++ b/src/algorithm_exercises_csharp_test/hackerrank/interview_preparation_kit/greedy_algorithms/GreedyFloristTest.cs @@ -0,0 +1,51 @@ +namespace algorithm_exercises_csharp_test.hackerrank.interview_preparation_kit.greedy_algorithms; + +using algorithm_exercises_csharp_test.common; +using algorithm_exercises_csharp.hackerrank.interview_preparation_kit.greedy_algorithms; + +/** + * GreedyFloristTest. + */ +[TestClass] +public class GreedyFloristTest +{ + public class GreedyFloristTestCase(string title, List c, int k, int expected) + { + public string Title { get; } = title; + public List C { get; } = c; + public int K { get; } = k; + public int Expected { get; } = expected; + } + + private List testCases { get; set; } = default!; + + [TestInitialize] + public void testInitialize() + { + testCases = JsonLoader.resourceLoad>( + "hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.testcases.json" + ) ?? []; + } + + [TestMethod] + public void testLuckBalance() + { + foreach (GreedyFloristTestCase test in testCases) + { + int[] inputArray = test.C.ToArray(); + int result = GreedyFlorist.getMinimumCost(test.K, inputArray); + + Assert.AreEqual( + test.Expected, + result, + string.Format( + System.Globalization.CultureInfo.InvariantCulture, + "getMinimumCost({0}, {1}) => must be: {2}", + test.K, + inputArray.ToString(), + test.Expected + ) + ); + } + } +}