Repository: TheAlgorithms/Java
Pull request #4504 (2023-10-01 14:52:20)

Greedy Algorithm Implementations and Explanations #4493
<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.


Vineetttt: > The code looks good, could you please remove `main`, logging to console, and add some JUnit tests? (see https://github.com/TheAlgorithms/Java/tree/master/src/test/java/com/thealgorithms)

@siriak Yes I'll do the changes but can you elaborate a bit, what exactly needs to be done
Vineetttt: @siriak I've made the necessary changes you can check.
Vineetttt: @siriak I've made the necessary changes you can check and merge accordingly.
siriak: Please fix the linter job which is failing and add more tests for coin change
Vineetttt: @siriak Necessary changes are made, you can check .

Patch:
diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java b/src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java
new file mode 100644
index 00000000..0f704dd6
--- /dev/null
+++ b/src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java
@@ -0,0 +1,40 @@
+package com.thealgorithms.greedyalgorithms;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+
+// Problem Link:  https://en.wikipedia.org/wiki/Activity_selection_problem
+
+public class ActivitySelection {
+    // Function to perform activity selection
+    public static ArrayList<Integer> activitySelection(int startTimes[], int endTimes[]) {
+        int n = startTimes.length;
+        int activities[][] = new int[n][3];
+
+        // Create a 2D array to store activities and their start/end times.
+        // Each row: [activity index, start time, end time]
+
+        for (int i = 0; i < n; i++) {
+            activities[i][0] = i; // Assign activity index
+            activities[i][1] = startTimes[i]; // Assign start time
+            activities[i][2] = endTimes[i]; // Assign end time
+        }
+
+        // Sort activities by their end times in ascending order.
+        Arrays.sort(activities, Comparator.comparingDouble(activity -> activity[2]));
+        int lastEndTime;
+        ArrayList<Integer> selectedActivities = new ArrayList<>();
+        selectedActivities.add(activities[0][0]);
+        lastEndTime = activities[0][2];
+
+        // Iterate through sorted activities to select compatible ones.
+        for (int i = 1; i < n; i++) {
+            if (activities[i][1] >= lastEndTime) {
+                selectedActivities.add(activities[i][0]);
+                lastEndTime = activities[i][2];
+            }
+        }
+        return selectedActivities;
+    }
+}
diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java b/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java
new file mode 100644
index 00000000..2109e454
--- /dev/null
+++ b/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java
@@ -0,0 +1,35 @@
+package com.thealgorithms.greedyalgorithms;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+
+// Problem Link : https://en.wikipedia.org/wiki/Change-making_problem
+
+public class CoinChange {
+    // Function to solve the coin change problem
+    public static ArrayList<Integer> coinChangeProblem(int amount) {
+        // Define an array of coin denominations in descending order
+        Integer coins[] = {1, 2, 5, 10, 20, 50, 100, 500, 2000};
+
+        // Sort the coin denominations in descending order
+        Arrays.sort(coins, Comparator.reverseOrder());
+
+        int count = 0; // Variable to keep track of the total number of coins used
+        ArrayList<Integer> ans = new ArrayList<>(); // List to store selected coins
+
+        // Iterate through the coin denominations
+        for (int i = 0; i < coins.length; i++) {
+            // Check if the current coin denomination can be used to reduce the remaining amount
+            if (coins[i] <= amount) {
+                // Repeatedly subtract the coin denomination from the remaining amount
+                while (coins[i] <= amount) {
+                    count++; // Increment the count of coins used
+                    ans.add(coins[i]); // Add the coin to the list of selected coins
+                    amount -= coins[i]; // Update the remaining amount
+                }
+            }
+        }
+        return ans;
+    }
+}
diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java b/src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java
new file mode 100644
index 00000000..c5570f35
--- /dev/null
+++ b/src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java
@@ -0,0 +1,41 @@
+package com.thealgorithms.greedyalgorithms;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+// Problem Link: https://en.wikipedia.org/wiki/Continuous_knapsack_problem
+
+public class FractionalKnapsack {
+    // Function to perform fractional knapsack
+    public static int fractionalKnapsack(int weight[], int value[], int capacity) {
+        // Create a 2D array to store item indices and their value-to-weight ratios.
+        double ratio[][] = new double[weight.length][2];
+
+        // Populate the ratio array with item indices and their value-to-weight ratios.
+        for (int i = 0; i < weight.length; i++) {
+            ratio[i][0] = i; // Assign item index.
+            ratio[i][1] = value[i] / (double) weight[i]; // Calculate and assign value-to-weight ratio.
+        }
+
+        // Sort items by their value-to-weight ratios in descending order.
+        Arrays.sort(ratio, Comparator.comparingDouble(o -> o[1]));
+
+        int finalValue = 0; // Variable to store the final knapsack value.
+        double current = capacity; // Variable to track the remaining capacity of the knapsack.
+
+        // Iterate through the sorted items to select items for the knapsack.
+        for (int i = ratio.length - 1; i >= 0; i--) {
+            int index = (int) ratio[i][0]; // Get the item index.
+            if (current >= weight[index]) {
+                // If the entire item can fit in the knapsack, add its value.
+                finalValue += value[index];
+                current -= weight[index];
+            } else {
+                // If only a fraction of the item can fit, add a proportionate value.
+                finalValue += ratio[i][1] * current;
+                break; // Stop adding items to the knapsack since it's full.
+            }
+        }
+        return finalValue;
+    }
+}
diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java b/src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java
new file mode 100644
index 00000000..bf81e067
--- /dev/null
+++ b/src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java
@@ -0,0 +1,65 @@
+package com.thealgorithms.greedyalgorithms;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+// Problem Link: https://en.wikipedia.org/wiki/Job-shop_scheduling
+
+public class JobSequencing {
+
+    // Define a Job class that implements Comparable for sorting by profit in descending order
+    static class Job implements Comparable<Job> {
+        char id;
+        int deadline;
+        int profit;
+
+        // Compare jobs by profit in descending order
+        @Override
+        public int compareTo(Job otherJob) {
+            return otherJob.profit - this.profit;
+        }
+
+        public Job(char id, int deadline, int profit) {
+            this.id = id;
+            this.deadline = deadline;
+            this.profit = profit;
+        }
+    }
+
+    // Function to print the job sequence
+    public static String findJobSequence(ArrayList<Job> jobs, int size) {
+        Boolean[] slots = new Boolean[size];
+        Arrays.fill(slots, false);
+
+        int result[] = new int[size];
+
+        // Iterate through jobs to find the optimal job sequence
+        for (int i = 0; i < size; i++) {
+            for (int j = jobs.get(i).deadline - 1; j >= 0; j--) {
+                if (!slots[j]) {
+                    result[j] = i;
+                    slots[j] = true;
+                    break;
+                }
+            }
+        }
+
+        // Create a StringBuilder to build the job sequence string
+        StringBuilder jobSequenceBuilder = new StringBuilder();
+        jobSequenceBuilder.append("Job Sequence: ");
+        for (int i = 0; i < jobs.size(); i++) {
+            if (slots[i]) {
+                jobSequenceBuilder.append(jobs.get(result[i]).id).append(" -> ");
+            }
+        }
+
+        // Remove the trailing " -> " from the job sequence
+        if (jobSequenceBuilder.length() >= 4) {
+            jobSequenceBuilder.setLength(jobSequenceBuilder.length() - 4);
+        }
+
+        // Return the job sequence as a string
+        return jobSequenceBuilder.toString();
+    }
+}


Test patch:
diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java
new file mode 100644
index 00000000..42263ac1
--- /dev/null
+++ b/src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java
@@ -0,0 +1,42 @@
+package com.thealgorithms.greedyalgorithms;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.junit.jupiter.api.Test;
+
+public class ActivitySelectionTest {
+    @Test
+    public void testActivitySelection() {
+        int start[] = {1, 3, 0, 5, 8, 5};
+        int end[] = {2, 4, 6, 7, 9, 9};
+
+        ArrayList<Integer> result = ActivitySelection.activitySelection(start, end);
+        ArrayList<Integer> expected = new ArrayList<>(Arrays.asList(0, 1, 3, 4));
+
+        assertEquals(expected, result);
+    }
+
+    @Test
+    public void testSingleActivity() {
+        int start[] = {1};
+        int end[] = {2};
+
+        ArrayList<Integer> result = ActivitySelection.activitySelection(start, end);
+        ArrayList<Integer> expected = new ArrayList<>(Arrays.asList(0));
+
+        assertEquals(expected, result);
+    }
+
+    @Test
+    public void testNoOverlap() {
+        int start[] = {1, 2, 3};
+        int end[] = {2, 3, 4};
+
+        ArrayList<Integer> result = ActivitySelection.activitySelection(start, end);
+        ArrayList<Integer> expected = new ArrayList<>(Arrays.asList(0, 1, 2));
+
+        assertEquals(expected, result);
+    }
+}
diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java
new file mode 100644
index 00000000..e9d26771
--- /dev/null
+++ b/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java
@@ -0,0 +1,58 @@
+package com.thealgorithms.greedyalgorithms;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.junit.jupiter.api.Test;
+
+public class CoinChangeTest {
+    @Test
+    public void testCoinChangeProblemWithValidAmount() {
+        ArrayList<Integer> expected = new ArrayList<>(Arrays.asList(500, 50, 20, 20, 1));
+        ArrayList<Integer> coins = CoinChange.coinChangeProblem(591);
+        assertEquals(expected, coins);
+    }
+
+    @Test
+    public void testCoinChangeProblemWithLargeAmount() {
+        ArrayList<Integer> expected = new ArrayList<>(Arrays.asList(2000));
+        ArrayList<Integer> coins = CoinChange.coinChangeProblem(2000);
+        assertEquals(expected, coins);
+    }
+
+    @Test
+    public void testCoinChangeProblemWithPartialCoins2() {
+        ArrayList<Integer> expected = new ArrayList<>(Arrays.asList(500, 50, 20));
+        ArrayList<Integer> coins = CoinChange.coinChangeProblem(570);
+        assertEquals(expected, coins);
+    }
+
+    @Test
+    public void testCoinChangeProblemWithSmallAmount() {
+        ArrayList<Integer> expected = new ArrayList<>(Arrays.asList(2, 1));
+        ArrayList<Integer> coins = CoinChange.coinChangeProblem(3);
+        assertEquals(expected, coins);
+    }
+
+    @Test
+    public void testCoinChangeProblemWithLargeAmountAndMultipleDenominations() {
+        ArrayList<Integer> expected = new ArrayList<>(Arrays.asList(2000, 2000, 2000, 2000, 500, 500, 500, 100, 100, 100, 100, 50, 20, 20, 5, 2, 2));
+        ArrayList<Integer> coins = CoinChange.coinChangeProblem(9999);
+        assertEquals(expected, coins);
+    }
+
+    @Test
+    public void testCoinChangeProblemWithAllDenominations() {
+        ArrayList<Integer> expected = new ArrayList<>(Arrays.asList(2000, 500, 100, 100, 100, 50, 20, 10, 5, 2, 1));
+        ArrayList<Integer> coins = CoinChange.coinChangeProblem(2888);
+        assertEquals(expected, coins);
+    }
+
+    @Test
+    public void testCoinChangeProblemWithZeroAmount() {
+        ArrayList<Integer> expected = new ArrayList<>();
+        ArrayList<Integer> coins = CoinChange.coinChangeProblem(0);
+        assertEquals(expected, coins);
+    }
+}
diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java
new file mode 100644
index 00000000..edbf0a09
--- /dev/null
+++ b/src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.greedyalgorithms;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+public class FractionalKnapsackTest {
+
+    @Test
+    public void testFractionalKnapsackWithExampleCase() {
+        int weight[] = {10, 20, 30};
+        int value[] = {60, 100, 120};
+        int capacity = 50;
+        assertEquals(240, FractionalKnapsack.fractionalKnapsack(weight, value, capacity));
+    }
+
+    @Test
+    public void testFractionalKnapsackWithZeroCapacity() {
+        int weight[] = {10, 20, 30};
+        int value[] = {60, 100, 120};
+        int capacity = 0;
+        assertEquals(0, FractionalKnapsack.fractionalKnapsack(weight, value, capacity));
+    }
+
+    @Test
+    public void testFractionalKnapsackWithEmptyItems() {
+        int weight[] = {};
+        int value[] = {};
+        int capacity = 50;
+        assertEquals(0, FractionalKnapsack.fractionalKnapsack(weight, value, capacity));
+    }
+}
diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java
new file mode 100644
index 00000000..8dd42bc7
--- /dev/null
+++ b/src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java
@@ -0,0 +1,23 @@
+package com.thealgorithms.greedyalgorithms;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import org.junit.jupiter.api.Test;
+
+public class JobSequencingTest {
+    @Test
+    public void testJobSequencingWithExampleCase() {
+        ArrayList<JobSequencing.Job> jobs = new ArrayList<>();
+        jobs.add(new JobSequencing.Job('a', 2, 100));
+        jobs.add(new JobSequencing.Job('b', 1, 19));
+        jobs.add(new JobSequencing.Job('c', 2, 27));
+        jobs.add(new JobSequencing.Job('d', 1, 25));
+        jobs.add(new JobSequencing.Job('e', 3, 15));
+        Collections.sort(jobs);
+        String jobSequence = JobSequencing.findJobSequence(jobs, jobs.size());
+
+        assertEquals("Job Sequence: c -> a -> e", jobSequence);
+    }
+}