How to find max number of participant who can perform? - java

I am trying to solve a question which has the following description:
At a time only one person can perform on the stage and arrival time and duration of each participant is given in the form of an array. Find the max number of participants who can perform.
Example:
arrival time: [1,3,3,5,7]
duration: [2,2,1,2,1]
answer would be 4, as 1-3; 3-5 or 3-4; 5-7; 7-8
So from this, I can find the exit time of each participant. How do I find max number of events possible, when there is overlap in timings.
The code I have tried is:
int count = 1;
for(int i=0;i<entry.size()-1;i++) {
if(entry.get(i) < exit.get(i+1)) {
count++;
}
}
return count;
I found the exit list using arrival + duration, but many tests are failing. The above example passes, but there might be instances where the overlapping time may have more participants possible.
I am not able to figure out how to proceed.

Updated answer as a new test case was added which made it clear the performers can be reordered if they have the same arrival time.
2nd update: Sort the input on the end time of each performer (arrival+duration).
Keep the endTime of the current performer. Only performers can perform which arrive after the end of the current performer.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class LifeGig {
public static class Performer {
int arrival, duration;
Performer(int arrival, int duration) {
this.arrival = arrival;
this.duration = duration;
}
#Override
public String toString() {
return "Performer [arrival=" + arrival + ", duration=" + duration + "]";
}
}
public List<Performer> program(int[] entry,int[] duration)
{
List<Performer> performers=new ArrayList<>();
for(int i=0;i<entry.length;i++)
{
performers.add(new Performer(entry[i],duration[i]));
}
Collections.sort(performers, new Comparator<Performer>() {
#Override
public int compare(Performer p1, Performer p2) {
return Integer.compare(p1.arrival+p1.duration, p2.arrival+p2.duration);
}
});
List<Performer> festival=new ArrayList<>();
System.out.println(performers);
int currentTime = 1;
for (Performer p:performers) {
if (p.arrival >= currentTime) {
currentTime = p.arrival+p.duration;
festival.add(p);
}
}
return festival;
}
public static void test1()
{
int[] entry = new int[] {1,3,3,5,7};
int[] duration = new int[] {2,2,1,2,1};
List<Performer> festival=new LifeGig().program(entry,duration);
System.out.println("Count (Expected=4): " + festival.size());
System.out.println("lineup:"+festival);
}
public static void test2()
{
int[] entry = new int[] {1, 1, 1, 1, 4};
int[] duration = new int[] {10, 3, 6, 4, 2};
List<Performer> festival=new LifeGig().program(entry,duration);
System.out.println("Count (Expected=2): " + festival.size());
System.out.println("lineup:"+festival);
}
public static void test3()
{
int[] entry = new int[] {1,2,3,4};
int[] duration = new int[] {10, 1,1,1,};
List<Performer> festival=new LifeGig().program(entry,duration);
System.out.println("Count (Expected=3): " + festival.size());
System.out.println("lineup:"+festival);
}
public static void main(String[] args) {
test1();
test2();
test3();
}
}

Since OP asked for a DP solution in a comment, and because it's not proven by the accepted answer that the greedy choice leads to an optimal solution, here's a DP solution. For any event, either it takes place or doesn't. The answer is the maximum of the two choices.
public class Solution {
private final List<Map.Entry<Integer, Integer>> events;
private final int[] startTimes;
private final Map<Integer, Integer> memo;
private static final Comparator<Map.Entry<Integer, Integer>> COMPARATOR =
Comparator.<Map.Entry<Integer, Integer>>comparingInt(Map.Entry::getKey)
.thenComparingInt(Map.Entry::getValue);
public Solution(int[] arrivals, int[] durations) {
events = IntStream.range(0, arrivals.length)
.mapToObj(i -> Map.entry(arrivals[i], arrivals[i] + durations[i]))
.sorted(COMPARATOR)
.collect(Collectors.toList());
startTimes = events.stream()
.mapToInt(Map.Entry::getKey)
.toArray();
memo = new HashMap<>();
}
private int loop(int i) {
if (i >= startTimes.length) {
return 0;
}
if (memo.containsKey(i)) {
return memo.get(i);
}
int ans = loop(i + 1);
int nextI = Arrays.binarySearch(startTimes, events.get(i).getValue());
if (nextI < 0) {
nextI = -nextI - 1;
}
ans = Math.max(ans, 1 + loop(nextI));
memo.put(i, ans);
return ans;
}
public static void main(String[] args) {
System.out.println(new Solution(new int[]{1, 3, 3, 5, 7}, new int[]{2, 2, 1, 2, 1}).loop(0));
System.out.println(new Solution(new int[]{1, 1, 1, 1, 4}, new int[]{10, 3, 6, 4, 2}).loop(0));
System.out.println(new Solution(new int[]{1, 2, 3, 4}, new int[]{10, 1, 1, 1}).loop(0));
}
}

Related

java.awt.Queue cannot be accessed from outside package

The version of java: SDK 1.8.0_151
IDE: IDEA IntelliJ
import java.awt.Queue;
import java.util.LinkedList;
public class SimpleMovingAverage {
private final Queue<Double> window = new LinkedList<Double>();
private final int period;
private double sum;
public SimpleMovingAverage(int period) {
assert period > 0 : "Period must be a positive integer";
this.period = period;
}
public void newNum(double num) {
sum += num;
window.add(num);
if (window.size() > period) {
sum -= window.remove();
}
}
public double getAvg() {
if (window.isEmpty()) {return 0.0;} // technically the average is undefined
return sum / window.size();
}
public static void main(String[] args) {
double[] testData = {1, 2, 3, 4, 5, 5, 4, 3, 2, 1};
int[] windowSizes = {3, 5};
for (int windSize : windowSizes) {
SimpleMovingAverage ma = new SimpleMovingAverage(windSize);
for (double x : testData) {
ma.newNum(x);
System.out.println("Next number = " + x + ", SMA = " + ma.getAvg());
}
System.out.println();
}
}
}
The code above is coming from https://rosettacode.org/wiki/Averages/Simple_moving_average#Java
When I create a Class, called SimpleMovingAverage and copy the code from the above website, an error is reported.
'java.awt.Queue' is not public in 'java.awt'. Cannot be accessed from outside package
How to solve it?
You need java.util.Queue not java.awt.Queue, which can hold whatever you want
The java.awt package is about UI, graphics and images: Documentation, and the java.awt.Queue is here to hold java.awt.Event elements
For Improvement ONLY : for the implementation of a Circular FIFO, here some infos
Is there a fixed sized queue which removes excessive elements?
Basic implem of a CircularQueue
Which could give something like
public void newNum(double num) {
window.add(num);
}

Java Recursion Pass by Reference in ArrayList

I am working on a problem to find which all combinations of integer in a given list can sum up to a given number.
public class SumProblem {
/*
* Input 2-2-3-7
* Output 2+2+3 and 7
*/
public static ArrayList<ArrayList<Integer>> find(ArrayList<Integer> input, int requiredSum) {
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
find(result, requiredSum, 0, new ArrayList<>(), 0, input);
return result;
}
public static void find(ArrayList<ArrayList<Integer>> result , int requiredSum , int currentSum, ArrayList<Integer> partialResult, int i, ArrayList<Integer> input) {
if (currentSum == requiredSum ) {
ArrayList<Integer> temp = new ArrayList<>();
temp = (ArrayList<Integer>) partialResult.clone();
result.add(temp);
return;
}
if (i >= input.size()) {
return;
}
find(result, requiredSum, currentSum , partialResult, i +1, input );
partialResult.add(input.get(i));
find(result, requiredSum, currentSum + input.get(i) , partialResult, i +1, input );
}
public static void main(String[] args) {
ArrayList<Integer> input = new ArrayList<>();
input.add(2);
input.add(1);
input.add(3);
ArrayList<ArrayList<Integer>> output = find(input, 3);
System.out.println(output.toString());
}
}
I have written code below.
I am facing one problem. In the below line of code, it is adding up all the numbers i traverse even if i create new ArrayList object and assign it to partialResult.
partialResult.add(input.get(i));
Could anyone suggest the solution ?
You have two recursive calls in this dynamic programming solution to the problem. One is supposed to not include the current value in the result, the other does.
You need to make a defensive copy of partialResult, otherwise both recursive calls are going to have a reference to the same list. A list is a mutable object. If both calls get a reference to the same list object, then when you add something to it anywhere, both of them will see the modified list.
The easiest way to make a defensive copy of a list is just to write:
new ArrayList<>(partialResult)
Here is a working version of the program:
import java.util.*;
public class SumProblem {
public static List<List<Integer>> find(List<Integer> input, int requiredSum) {
List<List<Integer>> result = new ArrayList<>();
find(result, requiredSum, 0, new ArrayList<>(), 0, input);
return result;
}
public static void find(List<List<Integer>> result, int requiredSum, int currentSum,
List<Integer> partialResult, int i, List<Integer> input) {
if (currentSum == requiredSum) {
result.add(new ArrayList<>(partialResult)); // add a copy of the list
return;
}
if (i >= input.size()) {
return;
}
// make defensive copies in the recursive calls
find(result, requiredSum, currentSum, new ArrayList<>(partialResult), i + 1, input);
partialResult.add(input.get(i));
find(result, requiredSum, currentSum + input.get(i), new ArrayList<>(partialResult), i + 1, input);
}
public static void main(String[] args) {
List<Integer> input = List.of(2, 8, 2, 3, 4);
List<List<Integer>> output = find(input, 7);
System.out.println(output);
}
}
Output:
[[3, 4], [2, 2, 3]]
I've made a few other changes:
Use List<Integer> and List<List<Integer>> as the types (code to the interface)
Use List.of() to create the input list (added in Java 9)
Don't call toString() on objects passed to println — it's unneeded

How does this recursion make sense?

import java.util.*;
public class ArrayList5 {
static int max(ArrayList list) { // to be completed
if (list.size() == 0) {
return 0;
}
else
{
int first = (Integer) list.get(0);
list.remove(0);
if (first > max(new ArrayList(list)))
{
return first;
}
else
{
return max(list);
}
}
}
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList();
Collections.addAll(list, 4, 5, 3, 2, 3, 1, 3);
// int t=Console.readInt("Enter Target:");
int res1 = max(new ArrayList(list));
System.out.println("max=" + res1);
}
}
I don't understand why the max(new ArrayList(list))) part is required. Why does it have to create a new one and why can't it continue to work with the one list?
Also why doesn't it get caught in a loop (it's recursion so it will keep sending up a new list so I don't understand why 'first' isn't going to be 4 every time)?
Actually, there is a lot of superfluous code that is not required and make the code cumbersome/more difficult to read/understand.
You can simplify the code a lot and get rid of any reference to ArrayList which are not really necessary and by using proper generic at the right places, make the code actually readable.
You don't need to cast or create list all over the place.
public class ArrayList5 {
static int max(final List<Integer> list) {
if(list.isEmpty()) return 0;
final int head = list.get(0);
final List<Integer> tail = list.subList(1, list.size());
return (head > max(tail)? head:max(tail));
}
public static void main(final String... args) {
final int res1 = max(Arrays.asList(4, 5, 3, 2, 3, 1, 3));
System.out.printf("max=%d", res1);
}
}
You should try this:
static int max(ArrayList<Integer> list) {...}
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList();
Collections.addAll(list, 4, 5, 3, 2, 3, 1, 3);
// int t=Console.readInt("Enter Target:");
int res1 = max(new ArrayList(list));
System.out.println("max=" + res1);
}
The compiler is probably throws a warning because you don't declare the type of the ArrayList.

Counting Repeated Elements in Given Array

How to count repeated elements in given array? Please give me any suggestion as an alternative for this problem.
public static void main(String[] args)
{
// TODO Auto-generated method stub
int a[]={1,2,3,1,2,4,4,4,5};
int c=0;
for(int i=0;i!='\0';i++)
{
c=1;
for(int k=i+1;k<9;k++)
{
if(a[i]==a[k] && a[i]!='\0')
{
c++;
// a[k]='\0';
}
}
if(a[i]!='\0')
{
System.out.println("value is"+a[i]+"repeated in"+c);
System.out.println("\n");
}
}
}
Here's another simple approach that does not require a separate data structure:
Sort the array using Arrays static method
Now you can iterate over the array knowing all duplicates will be grouped together. Shouldn't be hard to figure out....
Pilfering my code from another answer:
public static void main(String[] args) throws Exception {
int[] a = {1, 2, 3, 1, 2, 4, 4, 4, 5};
final Counter<Integer> counter = new Counter<>();
IntStream.of(a).forEach(counter::add);
IntStream.rangeClosed(1, 5).forEach(i -> {
System.out.printf("%s has a count of %s%n", i, counter.count(i));
});
}
public static class Counter<T> {
final Map<T, Integer> counts = new HashMap<>();
public void add(T t) {
counts.merge(t, 1, Integer::sum);
}
public int count(T t) {
return counts.getOrDefault(t, 0);
}
}
Output:
1 has a count of 2
2 has a count of 2
3 has a count of 1
4 has a count of 3
5 has a count of 1

comparing values of two arrays if exist or not

I have this code which is to check in the two arrays and print out the values that dont exist in the other array. I think the way i did it is not the most efficient way to do it hence can anyone offer a better OOP way to write this code in Java?
Thanks
public class Calculate {
static int [] x = {1,2,4,6,7};
static int [] y = {2,3,4,6,7};
static boolean xflag = true;
static boolean yflag = true;
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i = 0; i<x.length; i++)
{
for (int b=0; b<y.length; b++)
{
if(x[i]!= y[b])
{
xflag= false;
}
else
{
xflag = true;
break;
}
}
if(xflag==false)
{
System.out.println(x[i] +" does not exist in array 2");
}
}
for(int i = 0; i<x.length; i++)
{
for (int b=0; b<y.length; b++)
{
if(y[i]!= x[b])
{
yflag= false;
}
else
{
yflag = true;
break;
}
}
if(yflag==false)
{
System.out.println(y[i] +" does not exist in array1");
}
}
}
}
Using Collection class removeAll method
String original[] = { "1","2","3","4","6"};
String testStr[] = { "1","2","3","5","7" };
List origList = new ArrayList(Arrays.asList(original));
List testList = new ArrayList(Arrays.asList(testStr));
System.out.println(origList.removeAll(testList));
System.out.println(origList);
you can use java collection framework, Many function are there,
here is simple example check it.
public static void main(String a[]){
List<String> sl = new ArrayList<String>();
sl.add("apple");
sl.add("java");
sl.add("c++");
sl.add("unix");
sl.add("orange");
sl.add("airtel");
List<String> tl = new ArrayList<String>();
tl.add("job");
tl.add("oracle");
tl.add("jungle");
tl.add("cricket");
boolean isCommon = Collections.disjoint(sl,tl);
System.out.println("Does not found any common elements? "+isCommon);
tl.add("java");
isCommon = Collections.disjoint(sl,tl);
System.out.println("Does not found any common elements? "+isCommon);
}
You may use Apache's CollectionUtils for this purpose if you want an abstraction from the implementation logic.E.g:
public static void main(String[] args) {
List<Integer> list1=Arrays.asList(1,2,4,6,7);
List<Integer> list2=Arrays.asList(2,3,4,6,7);
System.out.println(CollectionUtils.disjunction(list1,list2));
}
You can code this way
List<Integer> array1 = Arrays.asList(1,2,4,6,7);
List<Integer> array2 = Arrays.asList(2,3,4,6,7);
List<Integer> disjointArray = new ArrayList<Integer>();
for (Integer value : array1) {
if (!array2.contains(value)) {
disjointArray.add(value);
}
}
And then you can print disjointArray or do whatever manipulation you want.
Here a running example using Javas Collection classes:
public class Disjunction {
public static void main(String args[]) throws UnsupportedEncodingException {
//Some data preparation
List<Integer> list1=Arrays.asList(1,2,4);
List<Integer> list2=Arrays.asList(5,2,8);
//Here calculating data1-data2 and data2-data1, collect all list items
//that are in data1 or in data2 but not in both.
List<Integer> data1 = new ArrayList<>(list1);
data1.removeAll(list2);
List<Integer> data2 = new ArrayList<>(list2);
data2.removeAll(list1);
//Merging both results. data1 contains now exclusive or of list1 and list2
data1.addAll(data2);
System.out.println("exclusive or is " + data1);
}
}
It prints out
exclusive or is [1, 4, 5, 8]
Try the following program that checks two arrays for numbers they both have and numbers they don't have:
package test;
import java.util.ArrayList;
public class ArrayDifferentiater {
public static void main(String[] args) {
int[] ori = { 1, 5, 4, 8, 6, 65, 16, 6, 575, 64, 561, 57, 57 };
int[] che = { 1, 4, 8, 6 };
sort(ori, che);
}
public static void sort(int[] a, int[] b) {
/**
* 'foundNum' contains the numbers which exists in both array.
* 'notFoundNum' contains the numbers which exists in only first array.
*/
ArrayList<Integer> foundNum = new ArrayList<>();
ArrayList<Integer> notFoundNum = new ArrayList<>();
// First for loop starts
for (int i = 0; i < a.length; i++) {
// Second for loop starts
for (int j = 0; j < b.length; j++) {
/**
* Check if array 1 contains value of array 2.
* If contains than add it to "foundNum" arraylist.
*/
if (a[i] == b[j]) {
foundNum.add(a[i]);
// Remove the number which exists in both arrays from "notFoundNum" arraylist.
if (notFoundNum.contains(a[i])) {
for (int k = 0; k < notFoundNum.size(); k++) {
if (notFoundNum.get(k) == a[i]) {
notFoundNum.remove(k);
}
}
}
break;
} // First if block ends
/**
* Checks if a not found number does not exists in 'notFoundNum' arraylist (to reduce redundancy)
* then adds a not found number to 'notFoundNum' arraylist
* */
if (!notFoundNum.contains(a[i]))
notFoundNum.add(a[i]);
} // Second for loop ends
} // First for loop ends
System.out.println("Found Numbers : " + foundNum);
System.out.println("Not Found Numbers : " + notFoundNum);
}
}
Here is the output for the above program:
Found Numbers : [1, 4, 8, 6, 6]
Not Found Numbers : [5, 65, 16, 575, 64, 561, 57]

Categories

Resources