Related
I want to see if there is a efficient method to compare counts like (Acount, BCount, CCount,DCount, ECount) and evaluate the which count is largest in JAVA?
The program can use recursion but I wanted to know any optimized method to achieve this.
There are many ways to do this, it is up to whichever you find easier to read.
You could firstly use an IntStream:
int max = IntStream.of(ACount, BCount, CCount, DCount, ECount).max().getAsInt();
or, you could use an array of integers either manually going through each value:
int[] list = {ACount, BCount, CCount, DCount, ECount};
int max = Integer.MIN_VALUE;
for (int i : list) {
if (i > max) max = i;
}
or sorting the list and grabbing the largest value. This might be better if you have to access the smallest value as well.
int[] list = {ACount, BCount, CCount, DCount, ECount};
Arrays.sort(list);
int max = list[list.length - 1];
or, you could just use nested math max methods:
int max = Math.max(Math.max(Math.max(ACount, BCount), CCount), Math.max(DCount, ECount));
However, it is important to note that computers are fast enough to not need every small optimization. Something as small as comparing 5 int values will not take long no matter how you do it, so it is generally better to make your code more readable rather than more efficient in these situations, as often the minuscule gain is not worth the decrease in readability.
You have to compare n values, so I don't think it's possible to do this better than O(n).
The "efficiency" depends on your use case. If you only have 5 values, and you only need to do it once, then I'd argue that starting up a stream is probably not going to be the best approach. Though it may not be very important, since the loss of a few milliseconds just once is usually not a big deal. But if you get the JVM to JIT (Just In Time Compilation) with running it for a billion values, then checking out the different runtimes is my preferred way to figure out the most "effective" way.
In the below you can run it with different values for how many ints are in the array and how many times you'd like to run your max function. As I mentioned, I've found that streams are not very efficient when I only have 5 values.
You should probably not be running the test on a workstation, since those have lots of other stuff they need to do. I've found my own to be very unpredictable when trying to time things, though it seems to consistently give me the best output for the justLoop method.
C:\..snip..>java Testing.java
Ternary : 23561
JustLoop : 12663
MathMax : 35049
Stream : 46596
The code just has 4 different ways of getting the max:
Using a ternary, that will write to the max on every loop
A regular for loop and an if-statement
Using Math.max() instead of the if-statement.
Using IntStream and its max() function.
It starts by creating an array of ints. Then it calls a timer function passing in one of the 4 different methods:
import java.util.stream.IntStream;
public class Testing {
public static void main(String args[]){
int repeat = 10000;
int arraySize = 10000;
int[] countsRandom = randomCounts(arraySize);
printIt("Ternary", timeIt(() -> regularLoopTernary(countsRandom), repeat));
printIt("JustLoop", timeIt(() -> justLoop(countsRandom), repeat));
printIt("MathMax", timeIt(() -> justLoopWithMathMax(countsRandom), repeat));
printIt("Stream", timeIt(() -> stream(countsRandom), repeat));
}
public static int regularLoopTernary(int[] counts) {
int max = Integer.MIN_VALUE;
for (int i : counts) {
max = i > max ? i : max;
}
return max;
}
public static int justLoop(int[] counts) {
int max = Integer.MIN_VALUE;
for (int i : counts) {
if (i > max) {
max = i;
}
}
return max;
}
public static int justLoopWithMathMax(int[] counts) {
int max = Integer.MIN_VALUE;
for (int i : counts) {
max = Math.max(max, i);
}
return max;
}
public static int stream(int[] counts) {
return IntStream.of(counts)
.max()
.orElseThrow();
}
// get some ints
public static int[] randomCounts(int amount) {
return IntStream.range(0, amount)
.map(i -> (int) (Math.random() * Integer.MAX_VALUE))
.toArray();
}
// get the averge time only
public static long timeIt(Runnable runMe, int times) {
long start = System.nanoTime();
for (int i = 0; i < times; i++) {
runMe.run();
}
return (System.nanoTime() - start) / times;
}
public static void printIt(String title, long averagetime) {
System.out.printf("%-10s : %d%n", title, averagetime);
}
}
Could anyone give me some clue about how could I Transform this code to recursion:
public class arrayExample {
public static void main (String[] args) {
int[] a = {2,2,2,2};
int[] b = {2,2,2,2};
int n = a.length;
int sum = 0;
for (int i = 0; i < n; i++) {
sum += a[i] * b[i];
}
System.out.println(sum);
}
}
So to do this do product with recursion.
You asked for a hint, so I'm not giving you the complete solution. When you want to process a list (or an array) recursively, the concept is nearly always:
public int recursiveFunction(List l, int carry) {
if (l.isEmpty()) {
return carry;
}
return recursiveFunction(l.subList(1, l.size()), operation(carry, l.get(0));
}
Where operation is whatever you want to do with your list. carry is used to provide an initial value (in the first call) and save the interim results.
You just have to change the code so it uses two arrays instead of one list and choose the correct operation.
Ok so hoping you have tried it before this is one possible way to code it.
public class ArrayExample {
public static void main (String[] args) {
int[] a = {2,2,2,2};
int[] b = {2,2,2,2};
int n = a.length;
int result = recurseSum(a, b, n-1);
System.out.println(result);
}
public static int recurseSum(int[] a, int[] b, int n){
if(n == 0)
return a[0]*b[0];
else{
return (a[n] * b[n]) + recurseSum(a,b,n-1);
}
}
}
This code is basically doing the same thing in the iteration.
The recursive call happens 4 times. When n hits 0, a[0]*b[0] is returned to the higher call. so basically from right to left it happens as follows:
a[3]*b[3] + a[2]*b[2] + a[1]*b[1] + a[0]*b[0]
One simple way to make a loop into a recursion is to answer these two questions:
What happens when the loop executes zero times?
If the loop has already executed n-1 times, how do I compute the result after the n-th iteration?
The answer to the first case produces your base case; the answer to the second question explains how to do the recursive invocation.
In your case, the answers are as follows:
When the loop executes zero times, the sum is zero.
When the loop executed n-1 times, add a[n] * b[n] to the previous result.
This can be translated into a recursive implementation
static int dotProduct(int[] a, int[] b, int n) {
... // your implementation here
}
I have a program that sums the common elements of two arrays. For that I used two for loops and if I have three then I could use three for loops. But how to sum the common elements of n number of arrays where n is coming during run time.
I don't know how to change the number of loops during run time or is there any other relevant concept for this ?
Here is the code I've tried for summing twoarrays:
import java.util.Scanner;
public class Sample {
public static void main(String... args)
{
Scanner sc=new Scanner(System.in);
int arr1[]={1,2,3,4,5},arr2[]={4,5,6,7,8},sum=0;
for (int i=0;i<arr1.length;i++)
{
for (int j=0;j<arr2.length;j++)
{
if (arr1[i]==arr2[j])
{
sum+=(arr1[i]);
}
}
}
}
}
There can be different implementation for that. You can use the following approach. Here is the pseudo code
use a 2D array to store the array. if the number of array is n and size is m then the array will be input[n][m]
Use a ArrayList commonItems to store the common items of. Initiate it with the elements of input[0]
Now iterate through the array for i = 1 to n-1. compare with every input[i], store only the common items of commonItems and input[i] at each step. You can do it by converting the input[i] into a list and by using retainAll method.
At the end of the iteration the commonItem list will contains the common numbers only. Now sum the value of this list.
There is actually a more general method, that also answers the question "how to change the number of loops during run time?".
The general question
We are looking for a way to implement something equivalent to this:
for (i1 = 0; i1 < k1; i1++) {
for (i2 = 0; i2 < k2; i2++) {
for (i3 = 0; i3 < k3; i3++) {
...
for (in = 0; in < kn; in++) {
f(x1[i1], x2[i2], ... xn[in]);
}
...
}
}
}
where, n is given at runtime and f is a function taking a list of n parameters, processing the current n-tuple.
A general solution
There is a general solution, based on the concept of recursion.
This is one implementation that produces the desired behavior:
void process(int idx, int n, int[][] x, int[] k, Object[] ntuple) {
if (idx == n) {
// we have a complete n-tuple,
// with an element from each of the n arrays
f(ntuple);
return;
}
// this is the idx'th "for" statement
for (int i = 0; i < k[idx]; i++) {
ntuple[idx] = x[idx][i];
// with this recursive call we make sure that
// we also generate the rest of the for's
process(idx + 1, n, x, k, ntuple);
}
}
The function assumes that the n arrays are stored in a matrix x, and the first call should look like this:
process(0, n, x, k, new Object[n]);
Practical considerations
The solution above has a high complexity (it is O(k1⋅k2⋅..⋅kn)), but sometimes it is possible to avoid going until the deepest loop.
Indeed, in the specific problem mentioned in this post (which requires summing common elements across all arrays), we can skip generating some tuples e.g. if already x2[i2] ≠ x1[i1].
In the recursive solution, those situations can easily be pruned. The specific code for this problem would probably look like this:
void process(int idx, int n, int[][] x, int[] k, int value) {
if (idx == n) {
// all elements from the current tuple are equal to "value".
// add this to the global "sum" variable
sum += value;
return;
}
for (int i = 0; i < k[idx]; i++) {
if (idx == 0) {
// this is the outer "for", set the new value
value = x[0][i];
} else {
// check if the current element from the idx'th for
// has the same value as all previous elements
if (x[idx][i] == value) {
process(idx + 1, n, x, k, value);
}
}
}
}
Assuming that the index of the element is not important: a[1] = 2 and a[5] = 2, you only need two nested loops.
First you need to put n-1 arrays in a list of sets. Then loop over nth array and check if each element exists in all of the sets in the list. If it does exist then add to total.
Background: Very new at Java, have little understanding. Would prefer a "point in the right direction" with explanation, if possible, than a copy/paste answer without explanation. If I want to stop being a novice, I need to learn! :)
Anyway, my goal is, as simply as possible, to be given 2 arrays numberList and winningNumbers, compare them, and return the percentage that numberList matches winningNumbers. Both array lengths will always be 10.
I have no idea where to start. I have been googling and going at this for 2 hours. My idea is to write a for loop that compares each individually integer in a string to one in the other, but I am not sure how to do that, or if there is a simpler method. I have little knowledge of arrays, and the more I google the more confused I become.
So far the only thing I have is
public double getPercentThatMatch(int[] winningNumbers) {}
numberList is preset.
one way you could approach it is to:
1) convert both lists to sets.
2) subtract one from the other. ie if 4 are the same, the resulting set will have the 6 values not the same
3) 10 - (size of resulting set) * 100 = %
Here's a runnable example of how you would compare the two arrays of ints to get a percent match.
public class LotteryTicket {
int[] numberList;
LotteryTicket(int... numbers) {
numberList = numbers;
}
public int getPercentThatMatch(int[] winningNumbers) {
Arrays.sort(numberList);
Arrays.sort(winningNumbers);
int i = 0, n = 0, match = 0;
while (i < numberList.length && n < winningNumbers.length) {
if (numberList[i] < winningNumbers[n]) {
i++;
} else if (numberList[i] > winningNumbers[n]) {
n++;
} else {
match++;
i++;
n++;
}
}
return match * 100 / winningNumbers.length;
}
public static void main(String[] args)
{
int[] winningNumbers = { 12, 10, 4, 3, 2, 5, 6, 7, 9, 1 };
LotteryTicket ticket = new LotteryTicket(5, 2, 6, 7, 8, 4, 3, 1, 9, 0);
int percentMatching = ticket.getPercentThatMatch(winningNumbers);
System.out.println(percentMatching + "%");
}
}
Output:
80%
Since you wanted to be pointed in the right direction, rather than havving proper code, and assuming you want to use arrays to solve the problem, try to put something like this in your method:
(loop through arrayA){
(loop through arrayB){
if (current arrayA number is equal to current arrayB number){
then increase match counter by one, since this exists.
also break out of current arrayB loop. (Check next arrayA now.)
}
}
}
When done: return 100*matchCount/totalCount, as a double
So for every index in one array, you check against every other index of the other array. Increase a counter each time there's a match, and you'll be able to get a ratio of matches. If you use an integer as a counter, remember that division with integers acts funky, so you'd need to throw to a double:
double aDoubleNumber = (double) intNumber / anotherIntNumber
The problem would be easier if we consider them set. Let you have two set -
Set<Integer> s1 = //a HashSet of Integer;
Set<Integer> s2 = //a HashSet of Integer;
Now make a copy of s1 for example s11 and do the following thing -
s1.retainAll(s2);
Now s1 contains only element of both sets - that is the intersection.
After that you can easily calculate the percentage
Edit: You can convert the array to a set easily by using the following code snippet (I am assuming you have array of int) -
Set<Integer> s1 = new HashSet<Integer>(Arrays.asList(somePrimiteiveIntArray));
I think this trick will works for other primitive type also.
Hope this will help.
Thanks a lot.
I am going to attempt to beat a dead horse and explain the easiest (conceptual) way to approach this problem I will include some code but leave a lot up to interpretation.
You have two arrays so I would change the overall method to something like this:
public double getPercentage(int[] arrayA, int[] arrayB) {
double percentage=0;
for(/*go through the first array*/) {
for(/*go through second array*/) {
if(arrayA[i]==arrayB[j]) { /*note the different indices*/
percentage++; /*count how many times you have matching values*/
/* NOTE: This only works if you don't have repeating values in arrayA*/
}
}
}
return (percentage/arrayA.length)*100; /*return the amount of times over the length times 100*/
}
You are going to move through the first array with the first loop and the second array with the second loop. So you go through every value in arrayB for each value in arrayA to check.
In my approach I tried storing the winning numbers in a Hashset (one pass iteration, O(n) )
And when iterating on the numberList, I would check for presence of number in Hashset and if so, I will increment the counter. (one pass iteration, so O(n) )
The percentage is thus calculated by dividing the counter with size of array.
See if the sample code makes sense:
import java.util.HashSet;
public class Arraycomparison {
public static void main(String ... args){
int[] arr0 = {1,4,2,7,6,3,5,0,3,9,3,5,7};
int[] arr1 = {5,2,4,1,3,7,8,3,2,6,4,4,1};
HashSet set = new HashSet();
for(int j = 0; j < arr1.length; j++){
set.add(arr1[j]);
}
double counter = 0;
for(int i = 0; i < arr0.length; i++){
if(set.contains(arr0[i])){
counter++;
}
}
System.out.println("Match percentage between arrays : " + counter/arr0.length*100);
}
}
You should use List over array, because that's a convenient way, but with array:
public class Winner {
public static void main(String... args) {
double result = getPercentThatMatch(new int[]{1,2,3,4,5}, new int[]{2,3,4,5,6});
System.out.println("Result="+result+"%");
}
public static double getPercentThatMatch(int[] winningNumbers,
int[] numberList) { // it is confusing to call an array as List
int match = 0;
for (int win : winningNumbers) {
for (int my : numberList ){
if (win == my){
System.out.println(win + " == " + my);
match++;
}
}
}
int max = winningNumbers.length; // assume that same length
System.out.println("max:"+max);
System.out.println("match:"+match);
double devide = match / max; // it won't be good, because the result will be intm so Java will trunc it!
System.out.println("int value:"+devide);
devide = (double) match / max; // you need to cast to float or double
System.out.println("float value:"+devide);
double percent = devide * 100;
return percent;
}
}
Hope this helps. ;)
//For unique elements
getpercentage(arr1, arr2){
res = arr1.filter(element=>arr2.includes(element))
return res.lenght/arr2.lenght * 100;
}
//For duplicate elements
getpercentage(arr1, arr2){
const setA = Set(arr1);
const setB = Set(arr2);
Let res = [ ];
for(let i of setB){
if(setA.has(i)){
res.push(i);
}
}
return res.lenght/setA.size* 100;
What I want to do
I want to find a subset of an array that sums to a target T. I also want to use to a dynamic programming approach (and a bottom-up solution at that) to do this.
What I currently have
Currently I only found a way to see if amongst all subsets of size N, whether or not there is at least one subset that has the desired sum. See code below.
public boolean solve(int[] numbers, int target) {
//Safeguard against invalid parameters
if ((target < 0) || (sum(numbers) < target)){
return false;
}
boolean [][] table = new boolean [target + 1] [numbers.length + 1] ;
for (int i = 0; i <= numbers.length; ++i) {
table[0][i] = true;
}
/* Base cases have been covered.
* Now look set subsets [1..n][target] to be true or false.
* n represents the number of elements from the start that have a subset
* that sums to target
*/
for (int i = 1; i <= target; ++i){
for (int j = 1; j <= numbers.length; ++j){
/* Mark index j as one of the numbers in the array
* which is part of the solution with the given subtarget */
table [i][j] = table[i][j-1];
if (i >= numbers[j-1])
table[i][j] = table[i][j] || table[i - numbers[j-1]] [j-1];
}
}
return table[target][numbers.length];
}
Where I am stuck
Right now, I know if there is a solution, but I can't think of a way to actually output a solution.
I am not looking for anyone to provide me specific code, but pseudocode is welcome as are hints to how a solution may be saved.
The algorithm you provided can stay the same, you don't need to store anything else besides the DP-table table[][]. You just need an additional post-processing phase in which you step "backwards" through table[][] to get the solution set.
Just to recall:
You've computed the table table[i][j], which stores for every value 0<=i<=t(:=target) and every 0<=j<=n(:=numbers.length) whether there is a subset of numbers in numbers[0..j-1] that sum to i.
Consider the subset S corresponding to table[i][j] (, which is true). Note that:
The subset S contains the number numbers[j] only if table[ i-numbers[j] ][j-1] is true.
(Proof: recursively take the solution subset S' for table[ i-numbers[j] ][j-1], and add numbers[j])
On the other hand, this subset S does not contain the number numbers[j] only if table[ i-numbers[j] ][j-1] is false.
(Proof: assume S contains numbers[j], trow numbers[j] out of S, this implies table[ i-numbers[j] ][j-1], contradiction)
So to get the subset, simply use the above property to check whether numbers[n-1] is in the subset summing to t.
If so, recursively compute whether numbers[n-2] is in the subset summing to t-numbers[n-1],
else recursively compute whether numbers[n-2], is in the subset summing to t
Here are the two Java solutions for the subset sum problem.
First using Recursive Approach.
Second using Dynamic Programming Approach.
/*
Question: Given a set of non-negative integers, and a value sum, determine if there is a subset of the given set
with sum equal to given sum.
Examples: set[] = {3, 34, 4, 12, 5, 2}, sum = 9
Output: True //There is a subset (4, 5) with sum 9.
Let isSubSetSum(int set[], int n, int sum) be the function to find whether there is a subset of set[] with
sum equal to sum. n is the number of elements in set[].
*/
package SubsetSumProblem;
import java.util.Scanner;
public class UsingResursiveAndDPApproach {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
try{
System.out.println("Enter the number of elements in the array");
int n =in.nextInt();
System.out.println("Enter the elements of the array");
int[] a=new int[n];
for(int i=0;i<n;i++)
a[i]=in.nextInt();
System.out.println("Enter the sum, which you need to find");
int sum = in.nextInt();
System.out.println("Using recursion, the result is: "+usingRecursion(a,a.length,sum));
System.out.println("Using Dynamic Programming, the result is: "+usingDP(a,sum));
}
finally{
in.close();
}
}
private static boolean usingRecursion(int[] a,int length, int sum) {
// 1. Base Cases
if(sum==0)
return true;
if(length==0 && sum!=0)
return false;
// 2. To avoid unnecessary steps, we will optimize the recursion method by avoiding
// recursive calls to areas where we are definite that we can SAFELY ignore the case since
// the SOLUTION does not exist there.
// If last element is greater than sum, then ignore it
if(a[a.length-1]>sum)
return usingRecursion(a,length-1,sum);
// 3. This is the recursion step where we will call the method again and again
/* else, check if sum can be obtained by any of the following
(a) including the last element
(b) excluding the last element */
return (usingRecursion(a, length-1, sum-a[length-1])|| usingRecursion(a, length-1, sum));
}
/*
Analysis:
Time Complexity = O(2^n)
Space Complexity = // Don't know
*/
private static boolean usingDP(int[] a, int sum) {
// using boolean matrix for DP
boolean dp[][] = new boolean[a.length+1][sum+1]; // +1 in row and column
// if the length of the array is variable (and sum is 0) then fill TRUE, since the SUM=0
for(int row=0;row<dp.length;row++){
dp[row][0] = true; // NOTE: dp[length=VARIABLE][sum=0], thus we satisfy the condition where length is VARIABLE
// and the SUM=0
}
// if the SUM is variable and length is 0 then FALSE, since (sum=variable && length=0)
for(int column=1;column<dp[0].length;column++){
dp[0][column] = false; // NOTE: dp[length=0][sum=VARIABLE], thus we satisfy the condition where
// (length=0 && sum=variable)
}
for(int i=1;i<dp.length;i++){
for(int j=1;j<dp[0].length;j++){
/* Check if sum can be obtained by any of the following
(a) including the last element
(b) excluding the last element */
// VERY VERY IMP: This is same as "excluding the last element" which is represented in DP
dp[i][j] = dp[i-1][j]; // the current position[i][j] would be same as previous position.
// the previous position means that SUM is ACHIEVED OR NOT-ACHIEVED
// int the previous position then it will ofcourse be ACHIEVED or NOT-ACHIEVED
// in the current position.
// VERY VERY IMP: This is same as "including the last element" which is represented in DP
// if the column[ sum is represented in column of the matrix i.e this sum exist] > = sum-a[last_index]
// then decrease the sum
if(j>=a[i-1]) // i.e sum >= array[last index element]. If it is true then include this last element by
// deducting it from the total sum
dp[i][j] = dp[i][j] || dp[i-1][j-a[i-1]]; // VERY VERY IMP NOTE: Here dp[i][j] on R.H.S represent
// dp[i-1][j] which we have assigned in the previous step
}
}
return dp[a.length][sum];
}
/*
Analysis:
Time Complexity = O(a.length*sum)
Space Complexity = O(a.length*sum)
*/
}
Here is my solution is an iterative dp, but with only one dimension: Hope it can help you.
#include <iostream>
#include <cstring>
using namespace std;
const int maxN=1000;
int memo[maxN];
int pi[maxN];
int main(){
int a[]={7,8,5,1,4};
memset(memo,-1,sizeof memo);
memset(pi,-1,sizeof pi);
int n;
cin>>n;
memo[0]=0;
pi[0]=0;
for(int i=0;i<(int)sizeof(a)/4;i++){
for(int num=n;num>=0;num--){
if(num-a[i]>=0 and memo[num-a[i]]!=-1 and (memo[num]==-1 or memo[num]>1+memo[num-a[i]])){
memo[num]=1+memo[num-a[i]];
pi[num]=num-a[i];
}
}
}
int N=n;
while(N!=0){
cout<<N-pi[N]<<" ";
N=pi[N];
}
cout<<endl;
cout<<memo[n]<<endl;
return 0;
}