Calculation of average required series of integers, equal to a defined double - java

Hello!
I am trying to make a Java program to generate a series of Integers from a given array, such that the average of the selected integers is equal to a user-defined double.
Now, let's say the User defines the target as 46.00.
ArrayList<Integer> usableItems = new ArrayList<>();
Here, the user specifies the size and each integer into the array. Like this.
System.out.println("Enter number of elements of usable integers: ");
int siz=0;
siz = Integer.parseInt(in.nextLine());
ArrayList<Integer> usableItems = new ArrayList<>();
for (int i=0 ; i<siz ; i++)
{
try {
int j = i+1;
System.out.println("Enter element "+j+": ");
usableItems.add(Integer.parseInt(in.nextLine()));
} catch (Exception e)
{
System.out.println(e.getMessage());
break;
}
}
Let's say, this is the specified array:
[20,25,30,35,50]
So, it should process now, so that I get this output:
Specified target = 46.00
Series = 50,50,50,50,30
As the average of the above outputted series is equal to 46.
The number of integers in the Series (which is 5), need not be equal to the size of the usableItems.
I tried to find an accurate algorithm, but I don't get it how to.
Any helps/suggestions are surely appreciated!

Brute-force recursive implementation returning the shortest possible series:
public List<Integer> matchAverage(double target, List<Integer> items) {
for (int i = 1; i <= 50; i++) { // arbitrary limit of 50
List<Integer> match = matchAverage(target, items, new ArrayList<>(), 0, i);
if (match != null) return match;
}
throw new RuntimeException("Average not found.");
}
private List<Integer> matchAverage(double target, List<Integer> items, List<Integer> selected, int sum, int left) {
for (int i = 0; i < items.size(); i++) {
Integer item = items.get(i);
selected.add(item);
sum += item;
if (left == 1) {
if (sum / (double) selected.size() == target) {
return selected;
}
} else {
List<Integer> match = matchAverage(target, items.subList(i, items.size()), selected, sum, left - 1);
if (match != null) return match;
}
sum -= item;
selected.remove(selected.size() - 1);
}
return null;
}
You can probably do this a lot faster by only checking items that get you closer to the target.

Related

*First* Longest Increasing Subsequence

The longest increasing subsequence is the well known problem and I have a solution with the patience algorithm.
Problem is, my solution gives me the "Best longest increasing sequence" instead of the First longest increasing sequence that appears.
The difference is that some of the members of the sequence are larger numbers in the first(but the sequence length is exactly the same).
Getting the first sequence is turning out to be quite harder than expected, because having the best sequence doesn't easily translate into having the first sequence.
I've thought of doing my algorithm then finding the first sequence of length N, but not sure how to.
So, how would you find the First longest increasing subsequence from a sequence of random integers?
My code snippet:
public static void main (String[] args) throws java.lang.Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int inputInt;
int[] intArr;
try {
String input = br.readLine().trim();
inputInt = Integer.parseInt(input);
String inputArr = br.readLine().trim();
intArr = Arrays.stream(inputArr.split(" ")).mapToInt(Integer::parseInt).toArray();
} catch (NumberFormatException e) {
System.out.println("Could not parse integers.");
return;
}
if(inputInt != intArr.length) {
System.out.println("Invalid number of arguments.");
return;
}
ArrayList<ArrayList<Integer>> sequences = new ArrayList<ArrayList<Integer>>();
int sequenceCount = 1;
sequences.add(new ArrayList<Integer>());
sequences.get(0).add(0);
for(int i = 1; i < intArr.length; i++) {
for(int j = 0; j < sequenceCount; j++) {
if(intArr[i] <= intArr[sequences.get(j).get(sequences.get(j).size() - 1)]) {
sequences.get(j).remove(sequences.get(j).size() - 1);
sequences.get(j).add(i);
break;
} else if (j + 1 == sequenceCount) {
sequences.add(new ArrayList<Integer>(sequences.get(j)));
sequences.get(j + 1).add(i);
sequenceCount++;
break; //increasing sequenceCount causes infinite loop
} else if(intArr[i] < intArr[sequences.get(j + 1).get(sequences.get(j + 1).size() - 1)]) {
sequences.set(j+ 1, new ArrayList<Integer>(sequences.get(j)));
sequences.get(j+ 1).add(i);
break;
}
}
}
int bestSequenceLength = sequenceCount;
ArrayList<Integer> bestIndexes = new ArrayList<Integer>(sequences.get(bestSequenceLength - 1));
//build bestSequence, then after it I'm supposed to find the first one instead
int[] bestSequence = Arrays.stream(bestIndexes.toArray()).mapToInt(x -> intArr[(int) x]).toArray();
StringBuilder output = new StringBuilder("");
for(Integer x : bestSequence) {
output.append(x + " ");
}
System.out.println(output.toString().trim());
}
I'm storing indexes instead in preparation for having to access the original array again. Since it's easier to go from indexes to values than vice versa.
Example:
3 6 1 2 8
My code returns: 1 2 8
First sequence is: 3 6 8
Another Example:
1 5 2 3
My code correctly returns: 1 2 3
Basically, my code works as long as the first longest sequence is the same as the best longest sequence. But when you have a bunch of longest sequences of the same length, it grabs the best one not the first one.
Code is self-explanatory. (Have added comments, let me know if you need something extra).
public class Solution {
public static void main(String[] args) {
int[] arr = {3,6,1,2,8};
System.out.println(solve(arr).toString());
}
private static List<Integer> solve(int[] arr){
int[][] data = new int[arr.length][2];
int max_length = 0;
// first location for previous element index (for backtracing to print list) and second for longest series length for the element
for(int i=0;i<arr.length;++i){
data[i][0] = -1; //none should point to anything at first
data[i][1] = 1;
for(int j=i-1;j>=0;--j){
if(arr[i] > arr[j]){
if(data[i][1] <= data[j][1] + 1){ // <= instead of < because we are aiming for the first longest sequence
data[i][1] = data[j][1] + 1;
data[i][0] = j;
}
}
}
max_length = Math.max(max_length,data[i][1]);
}
List<Integer> ans = new ArrayList<>();
for(int i=0;i<arr.length;++i){
if(data[i][1] == max_length){
int curr = i;
while(curr != -1){
ans.add(arr[curr]);
curr = data[curr][0];
}
break;
}
}
Collections.reverse(ans);// since there were added in reverse order in the above while loop
return ans;
}
}
Output:
[3, 6, 8]

Checking to see if an integer has distinct numbers java

I'm having a difficult time with my program! For this method I have to check to see if all the numbers are distinct and I can't figure out for the life of me what I am doing wrong. I don't know if using an array is the best way to go. I must call the getDigit method.
for (int i = 0; i <= numDigits(number); i++) {
int digit = getDigit(number,i);
if (digit == getDigit(number,i)) {
return false;
}
}
return true;
You can first get each digit from the number and add them to a HashSet, then compare the size of HashSet with the number of digits present in the number
You can try this code:
public static void main(String[] args) {
int val = 123554;
Set<Integer> set = new HashSet<Integer>(); // HashSet contains only unique elements
int count = 0; // keeps track of number of digits encountered in the number
// code to get each digit from the number
while (val > 0) {
int tempVal = val % 10;
set.add(tempVal); // add each digit to the hash set
// you can have a boolean check like if(!set.add(tempVal)) return false; because add() returns false if the element is already present in the set.
val = val / 10;
count++;
}
if (count == set.size()) {
System.out.println("duplicate digit not present");
} else {
System.out.println("duplicate digit present");
}
}
Splitting Int into single digits:
Use something similar to this:
Code to print the numbers in the correct order:
int number; // = and int
LinkedList<Integer> stack = new LinkedList<Integer>();
while (number > 0) {
stack.push( number % 10 );
number = number / 10;
}
while (!stack.isEmpty()) {
print(stack.pop());
}
Source
Checking for Duplicates:
Again, something similar to this:
public static boolean duplicates (int [] x, int numElementsInX ) {
Set<Integer> set = new HashSet<Integer>();
for ( int i = 0; i < numElementsInX; ++i ) {
if ( set.contains( x[i])) {
return true;
}
else {
set.add(x[i]);
}
}
return false;
}
Source
Alternative
If you can split the array, an alternative could be to use:
int[] numbers = { 1, 5, 23, 2, 1, 6, 3, 1, 8, 12, 3 };
Arrays.sort(numbers);
for(int i = 1; i < numbers.length; i++) {
if(numbers[i] == numbers[i - 1]) {
System.out.println("Duplicate: " + numbers[i]);
}
}
i suppose that you want to compare for example the number 12345 with 23145, and prompt out a false, and if they are the same (digit by digit, prompt a true) , am i right?.
If you want to do this, you should make 2 arrays and you have to make sure to compare each position of both so you can compare digit by digit.
Hope it helps you
public boolean unique(int theNumber) {
String number = new Integer(theNumber).toString();
Set<Character> set = new LinkedHashSet<Character>();
for(char c:number.toCharArray()) {
set.add(Character.valueOf(c));
}
return number.length() == set.size();
}

Creating multiple nested loops to generate two numbers that move through the length of a Array

As the title reads, I have been thinking about creating multiple nested loops that aim to achieve one purpose. Move two generated random numbers between 0-9 through each possible possition of an array.
For example, App generates first number (fNum) 1 and second number (sNum) 6. It then moves these numbers in the array which containts ABC. However firstNum and secondNum will need to also try all the possible combinations, so each one will need to be different with each loop.
-1ABC6
-A1BC6
-AB1C6
-ABC16
-ABC61
-AB6C1
-A6BC1
-6ABC1
-A6B1C
-A61BC
-A16BC
-A1B6C
-A1BC6
and so on...
I beleive the best way will be to create a method for generating a counter, which increments the numbers which I can call.
private int getNextNumber(int num) {
if (num == 0) {
return num;
} else {
num++;
}
if (num < 10) {
return num;
} else {
return -1;
}
}
Then I will need multiple nested loops... I have decided to go for several loops which will go infinitly.
while (j < maxlen) {
//J = 0 and maxlen = length of text so in this case 3 as it is ABC
//Add two numbers and check against answer
while (fNum != -1 || sNum != -1) {
//incrememnt numbers
fNum = getNextNumber(fNum);
System.out.println(fNum);
sNum = getNextNumber(sNum);
System.out.println(fNum);
}
String textIni = "ABC";
int lenOfText = textIni.length();
char[] split = textIni.toCharArray();
for (int i = 0; i < lenOfText; i++) {
//here it will look at the length of the Text and
//try the possible positions it could be at....
//maybe wiser to do a longer loop but I am not too sure
}
}
Since you don't need to store all possible combinations, we will save some memory using only O(n) storage with an iterative solution. I propose you a basic implementation but don't expect to use it on large arrays since it has a O(n³) complexity.
public static void generateCombinationsIterative(List<Integer> original, int fnum, int snum) {
int size = original.size();
for (int i=0 ; i<=size ; i++) {
List<Integer> tmp = new ArrayList<>(original);
tmp.add(i,fnum);
for (int j=0 ; j<=size + 1 ; j++) {
tmp.add(j,snum);
System.out.print(tmp + (i == size && j == size + 1 ? "" : ", "));
tmp.remove(j);
}
}
}
For your culture, here is an example of a recursive solution, which takes a lot of memory so don't use it if you don't need to generate the lists of results. Nevertheless, this is a more general solution that can deal with any number of elements to insert.
public static List<List<Integer>> generateCombinations(List<Integer> original, Deque<Integer> toAdd) {
if (toAdd.isEmpty()) {
List<List<Integer>> res = new ArrayList<>();
res.add(original);
return res;
}
int element = toAdd.pop();
List<List<Integer>> res = new LinkedList<>();
for (int i=0 ; i<=original.size() ; i++)
// you must make a copy of toAdd, otherwise each recursive call will perform
// a pop() on it and the result will be wrong
res.addAll(generateCombinations(insertAt(original,element,i),new LinkedList<>(toAdd)));
return res;
}
// a helper function for a clear code
public static List<Integer> insertAt(List<Integer> input, int element, int index) {
List<Integer> result = new ArrayList<>(input);
result.add(index,element);
return result;
}
Note that I did not use any array in order to benefit from dynamic data structures, however you can call the methods like this :
int[] arr = { 1,2,3 };
int fnum = 4, snum = 5;
generateCombinationsIterative(Arrays.asList(arr),fnum,snum);
generateCombinations(Arrays.asList(arr),new LinkedList<>(Arrays.asList(fnum,snum));
Note that both methods generate the combinations in the same order.

How to generate sums of combinations of elements of a set efficiently in terms of time and memory?

I have a random set S of integers and the cardinality (n) of this set may vary from 10 to 1000. I need to store all sums of the nCr combinations of size r generated from this set. Usually r range from 3 to 10.
E.g. if S={102,233,344,442,544,613,71289,836,97657,12} and r=4, Then The sums generated will be {0,1,2,3}=102+233+344+442, {0,1,2,4}=102+233+344+544,....so on.
I implemented a findCombi function (below) in Java which gave me all nCr combinations in terms of r sized sets of indices and then I sifted through these sets in another function to generate the sum of corresponding elements.
But the program is giving heapspace error, probably because of exponential nature and I have 100-5000 of such sets, S. Or may be there is a memory leak?
Is there a faster and lesser-memory consuming way to do it?
Note: dsize=n, combiSize=r
List <List<Integer>> findCombi(int dsize,int combiSize) {
if( (combiSize==0) || (dsize==0) ){
return null;
}
long n=dsize;
int r=combiSize;
for(int i=1;i<combiSize;i++) {
n=n*(dsize-i);
r=r*i;
}
int totalcombi=(int) n/r;
List <List<Integer>> combiData=new ArrayList<>(totalcombi);
int pos;
List <Integer> combi=new ArrayList<>(combiSize);
for(int i=0;i<combiSize;i++) {
combi.add(i,i);
}
combiData.add(new ArrayList<>(combi));
pos=combiSize-1;
while(true) {
if(combi.get(pos)<(dsize-combiSize+pos)) {
combi.set(pos,combi.get(pos)+1);
if(pos==(combiSize-1)) {
combiData.add(new ArrayList<>(combi));
}
else {
combi.set(pos+1,combi.get(pos));
pos++;
}
}
else {
pos--;
}
if(pos==-1) {
break;
}
}
return combiData;
}
I needed something like that earlier, so here is some code adapted from the project I made back then. The method allSums builds a list of indices of size r, which is used to represent all the possible combinations. At each step, the current sum is added to the result set, then the next combination is generated. Since the results are put in a set, there is no way a result could appear twice. I included a main method so you can see it work. I hope this is clear, feel free to ask questions.
import java.util.*;
public class Program {
static private Set<Integer> allSums(List<Integer> values, int r) {
HashSet<Integer> res = new HashSet<>();
if ((values.isEmpty()) || r > values.size()) {
return res;
}
// build the list of indices
List<Integer> li = new ArrayList<>();
for (int i = 0; i < r; i++) {
li.add(i);
}
li.add(values.size()); // artificial last index : number of elements in set
while (true) {
// add the current sum to the result
int sum = 0;
for (int i = 0; i < r; i++) {
sum += values.get(li.get(i));
}
res.add(sum);
// move to the next combination
// first, find the last index that can be incremented
int i = r-1;
while ((i >= 0) && (li.get(i) == li.get(i+1)-1)) {
i--;
}
// was such an index found ?
if (i == -1) {
break; // if not, it's over
}
// increment the last index and set all the next indices to their initial value
li.set(i,li.get(i)+1);
for (int j = i+1; j < r; j++) {
li.set(j, li.get(j-1)+1);
}
}
return res;
}
public static void main(String[] args) {
List<Integer> values = new ArrayList<>();
values.add(10);
values.add(100);
values.add(1000);
values.add(10000);
values.add(100000);
Set<Integer> s = allSums(values, 3);
for (int i : s) {
System.out.println(i);
}
}
}

Maximize sum with a limit

I have to get the highest sum of some numbers which do not exceeded a limit.
For Example with 5, 7, 14 and a limit of 13, I must choose 5 and 7.
This example is with only 3 numbers but I have to be able to do this with a lot more numbers.
Is there a library or a method to do this?
I'm assuming the allowed inputs are positive integers. This will return [7, 5] for the example in your question.
public class Knapsack {
private class State {
State previousState = null;
int value = 0;
}
public List<Integer> solve(List<Integer> list, int limit) {
// validate input
if (limit < 0) {
throw new IllegalArgumentException();
}
if (list == null) {
throw new IllegalArgumentException();
}
for (Integer i: list) {
if (i == null || i.intValue() <= 0) {
throw new IllegalArgumentException();
}
}
// if the limit is 12, then 0 through 12 inclusive are valid amounts
State[] states = new State[limit + 1];
// the state at position x represents a way of achieving a sum of x
// if a state is null it means we can't get that sum, for example in your
// question there's no way to get a sum of 11 with any combination of inputs
// base state -- we can always get a sum of zero if we just take nothing
states[0] = new State();
// build up more states
for (Integer i: list) {
// iterate through the states backwards
// if we iterate forwards we'll encounter any changes we make to the list
// during the iteration, which has the effect of taking the same number
// multiple times
for (int j = limit - i.intValue(); j >= 0; --j) {
if (states[j] != null) {
State newState = new State();
newState.previousState = states[j];
newState.value = i.intValue();
states[i.intValue() + j] = newState;
}
}
}
// find the best state
State s = null;
for (int i = limit; i >= 0; --i) {
if (states[i] != null) {
// if all you care about is the best achievable sum, you can just
// return i here
s = states[i];
break;
}
}
// build the list of numbers
List<Integer> ret = new ArrayList<Integer>();
while (s.previousState != null) {
// this will add them backwards, change to add to the beginning of the list
// to preserve the same order as the input
ret.add(Integer.valueOf(s.value));
s = s.previousState;
}
return ret;
}
public static void main(String[] arg) {
List<Integer> list = new ArrayList<Integer>();
for (int i: new int[] { 5, 7, 9 }) {
list.add(Integer.valueOf(i));
}
int limit = 13;
Knapsack k = new Knapsack();
System.out.println(k.solve(list, limit));
}
}

Categories