How to count duplicates in two unsorted arrays - java

I need to compare the guess and code arrays and count the number of correct digits in the guess.
It works until there are duplicate numbers in the code array. I know it's something to do with the second for loop and subtracting from the correctDigits.
public static int digits(int[] code, int[] guess) {
int digits = 0;
for (int i = 0; i < code.length; i++) {
for (int j = 0; j < guess.length; j++) {
if (guess[j] == code[i]) {
digits++;
break;
}
}
}
for (int i = 0; i < code.length; i++) {
for (int j = i + 1; j < code.length; j++) {
if (code[i] == code[j] && code[i] != guess[j] && code[j] != guess[i]) {
digits--;
}
}
}
return digits;
}

Since you mentioned "only using loops and basic knowledge" I assume concepts like maps are not included here and "basic knowledge" means "arrays".
If all you need to know is the number of digits try to convert your input to a 10-element array of counts, i.e. each digit would be the input.
Example:
int[] codeDigits = new int[10];
for (int i = 0; i < code.length; i++) {
codeDigits[code[i]]++;
}
This would turn [5,9,9,9] into [0,0,0,0,0,1,0,0,0,3], i.e. 5: 1x, 9: 3x
Now do this for the guess as well, e.g. [0,0,9,9] becomes [2,0,0,0,0,0,0,0,0,2].
Now all you have to do is count the number of digits:
int counter = 0;
for( int i = 0; i < codeDigits.length; i++ ) {
if( codeDigits[i] >= guessDigits[i] ) {
counter += guessDigits[i]; //guessed the exact number or less -> use the guess
} else {
counter += codeDigits[i]; //guessed more -> use the code
}
}
If you are able to use a Math function then the loop body could be replaced by counter += Math.min(codeDigits[i], guessDigits[i]);.
One more illustration (with longer codes to illustrate better):
code: [5,0,9,9,1,7,1] -> [1,2,0,0,0,1,0,1,0,2]
guess: [9,9,0,9,7,4,2] -> [1,0,1,0,1,0,0,1,0,3]
-----------------------------------------
minimum of each digit: 1,0,0,0,0,0,0,1,0,2
If you sum those minimums you get 4 correct digits: 1x 0, 1x 7, 2x 9

there are several solutions. one of them is indexing duplicated values of code array, then check them at first loop (and remove the 2nd loop):
int correctDigits = 0;
int[] duplicateIndexes = new int[code.length];
for (int i=0; i < code.length; i++) {
if( duplicateIndexes[i] == 1) continue;
for (int j=0; j < code.length; j++) {
if( core[i] == core[j]) {
duplicateIndexes[j] == 1;
continue;
}
}
}
for (int i = 0; i < code.length; i++) {
if (duplicatedIndexes[i] == 1) continue;
for (int j = 0; j < guess.length; j++) {
if (guess[j] == code[i]) {
correctDigits++;
break;
}
}
}

You can generate two Maps from these arrays, which associating a Value with its number of occurrences.
Then iterate over the entries of the Map obtained from the code array and compare its values with the corresponding values from the Map created based on the guess array. That would allow determining the number of correct/incorrect guesses.

I hope this will work.
Code
public static int getCorrectDigits(int[] code, int[] guess) {
if (code.length != guess.length) {
throw new IllegalArgumentException("Different lengths");
}
int correctDigits = 0;
for (int i = 0; i < code.length; i++) {
if (guess[i] == code[i]) {
correctDigits++;
}
}
return correctDigits;
}
Output
Code - 5 9 9 9
Guess - 0 9 9 9
Passes - 3
Code - 5 9 9 9
Guess - 9 9 0 0
Passes - 1
Code - 5 9 9 9
Guess - 0 0 9 9
Passes - 2
Code - 5 9 9 9
Guess - 9 0 0 0
Passes - 0

You need to change the for loop to iterate over the guess instead of iterate over the code array:
public static int getCorrectDigits(int[] code, int[] guess) {
if (code.length != guess.length) {
throw new IllegalArgumentException("Different lengths");
}
int correctDigits = 0;
for (int i = 0; i < guess.length; i++) {
for (int j = 0; j < code.length; j++) {
if (guess[i] == code[j]) {
correctDigits++;
break;
}
}
}
return correctDigits;
#Test
void ex1() {
assertEquals(3, ArrayComp.getCorrectDigits(new int[] {5,9, 9, 9}, new int[] {0,9,9,9}));
} #Test
void ex2() {
assertEquals(2, ArrayComp.getCorrectDigits(new int[] {5,9, 9, 9}, new int[] {9,9,0,0}));
} #Test
void ex3() {
assertEquals(2, ArrayComp.getCorrectDigits(new int[] {5,9, 9, 9}, new int[] {0,0,9,9}));
} #Test
void ex4() {
assertEquals(1, ArrayComp.getCorrectDigits(new int[]{5, 9, 9, 9}, new int[]{9, 0, 0, 0}));
}

I thought I'd join in on the fun - maintain a boolean array of code digits used, requires only one nested loop and reverse the looping order:
public static int getCorrectDigits(int[] code, int[] guess) {
if (code.length != guess.length) {
throw new IllegalArgumentException("Different lengths");
}
int correctDigits = 0;
boolean[] used = new boolean[code.length];
for (int i = 0; i < guess.length; i++) {
for (int j = 0; j < code.length; j++) {
if (guess[i] == code[j] && !used[j]) {
correctDigits++;
used[j] = true;
break;
}
}
}
return correctDigits;
}

Related

Compare and count in two arrays not in same order - Java

I need to count how many of the same digits are in the code vs. guess.
If code = [1, 2, 5, 6] and guess = [4, 1, 3, 2], it should return 2.
I can't directly change the parameter arrays, so I first created new arrays, sorted, then looped through to find how many are the same in both. The issue is that it returns 4 no matter what.
public static int digits(int[] code, int[] guess) {
int[] sortedCode = new int[code.length];
int[] sortedGuess = new int[guess.length];
int digits = 0;
for (int i = 0; i < code.length; i++) {
sortedCode[i] = code[i];
sortedGuess[i] = guess[i];
}
Arrays.sort(sortedCode);
Arrays.sort(sortedGuess);
for (int i = 0; i < code.length; i++) {
if (sortedGuess[i] == sortedCode[i]) {
digits++;
}
}
return digits;
As #Icarus mentioned in the comments, "you're comparing index to index when you should compare index to every index".
public static int getCorrectDigits(int[] code, int[] guess) {
int correctDigits = 0;
if (code.length != guess.length) {
throw new IllegalArgumentException("Different lengths");
}
for (int x = 0; x<code.length; x++){
for (int y = 0; y<guess.length; y++){
if (code[x] == guess[y]){
correctDigits++;
}
}
}
return correctDigits;
}
You can also convert the traditional for loop to an enhanced for loop.
for (int j : code) {
for (int i : guess) {
if (j == i) {
correctDigits++;
}
}
}

Arrays| Find repeating integers using array division?

How do I make the method show the repeated numbers. It seems a logical error that is stopping me and I don't know why the code doesn't do what it is supposed to do.
public static void findRepeating(int[] arr) {
for (int i = 0; i< arr.length; i++) {
for(int d = 0; d<arr.length; d++) {
if(arr[i] / arr[d] == 1) {
System.out.println(arr[i] + " is repeating");
}
}
}
}
public static void main(String[] args) {
int[] myArray = {69, 7, 8, 9, 90, 666, 69, 420, 2};
findRepeating(myArray);
}
}
Here is the correction, for the logic in inner for loop and the comparison
public static void findRepeating(int[] arr) {
for (int i = 0; i< arr.length; i++) {
for(int d = i+1; d<arr.length; d++) { //check with next element, as u will iterate over same element if iterating from start
if(arr[i] == arr[d]) { // checking for same number, as division can give 1 in multiple case for ex 11/7 is also 1
System.out.println(arr[i] + " is repeating");
}
}
}
}
Issue is with your if condition logic.
if (i != d && arr[i] / arr[d] == 1 && arr[i] % arr[d] == 0)
1) You should check that you are not dividing by the same array element. You can instead initialize the value of d from i+1 instead of 0.
2) Divide by should be equal to 1
3) There modulus should be 0 because division logic is not enough for this logic.
As #Eran said 9/8 and 9/9 will also result in 1 but with modulus check, we can ensure that we print that only 9 is repeating
public static void findRepeating(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int d = 0; d < arr.length; d++) {
if (i != d && arr[i] / arr[d] == 1 && arr[i] % arr[d] == 0) {
System.out.println(arr[i] + " is repeating");
}
}
}
}
public static void main(String[] args) {
int[] myArray = { 69, 7, 8, 9, 90, 666, 69, 420, 2 };
findRepeating(myArray);
}
The problem is already highlighted with your approach , but iterating over element again and again is not advisable when your array size is too high(time complexity of O(n^2) ) rather consider doing it as you iterate over the array in O(n) time with extra space of O(n)
Set<Integer> hs = new HashSet<Integer>(); // to store elements
for (int i = 0; i< arr.length; i++) {
if(hs.contains(arr[i])) { // Checking if element is present in set or not
System.out.println(arr[i] + " is repeating");
}else {
hs.add(arr[i]);
}
}
}
You need to exclude current i index from second loop condition. For a large optimalization, you could start iterating second loop from index i.
public static void findRepeating(int[] arr) {
if(arr.length<2) { return; } // edge case condition
for (int i = 0; i< arr.length; i++) {
for(int d = i+1; d<arr.length; d++) { // start from i+1 index
if( arr[i] == arr[d]) {
System.out.println(arr[i] + " is repeating");
}
}
}
}
Now it will print:
69 is repeating
Otherwise you will always print arr[i] as repeated.

Java sorting array positive ascending to negative ascending

I can't solve the problem , where I need output from array A like {1,2,3,4,-1,-2,-3,-4}
from random numbers in array, then write it to another array B. So far my experimental code doesn't work as I'd
public static void main(String[] args) {
int a[] = {5,4,3,2,1,-3,-2,-30};
int length = a.length - 1;
for (int i = 0 ; i < length ; i++) {
for (int j = 0 ; j < length-i ; j++) {
if (a[j] < a[j+1]) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
}
}
}
for (int x : a) {
System.out.print(x+" ");
}
}
Output is 5 4 3 2 1 -2 -3 -30 , but I need 1,2,3,4,5,-2,-3,-30
Update:
public static void main(String[] args) {
int a[] = {5,4,3,2,1,-3,-2,-30,-1,-15,8};
int length = a.length - 1;
for (int i = 0 ; i < length ; i++) {
for (int j = 0 ; j < length-i ; j++) {
if (a[j] < a[j+1]) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
} else {
if (a[j] > a[j+1] && a[j+1] > 0) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
}
}
}
}
for (int x : a) {
System.out.print(x+" ");
}
}
I got closer to my target but 8 1 2 3 4 5 -1 -2 -3 -15 -30 , that number 8 ruins it all
Add an if-else to differentiate the positive and negative case.
if (a[j] < 0) {
if (a[j] < a[j+1]) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
}
} else {
if (a[j] > a[j+1] && a[j+1] > 0) {
int swap = a[j];
a[j] = a[j+1];
a[j+1] = swap;
}
}
If I understand you correctly you want to sort after two things. Positive numbers from low to high and negative numbers from high to low.
You could first sort from high to low and in a second run over the array skip all positives and then sort from high to low.
Does this help?
I could write some code, but I believe that's something you want to learn right now :)
Algo:
Traverse the Array and Store positives in one and Negatives in another. O(i)
Sort the positives array in ascending order. O(mLog(m))
Sort the negatives indescending order. O(nLog(n))
Create a final array of the size of the input.
Add all the positive array sorted values. Then add the negative array sorted values. O(i)
Total : O(i) + O(mLog(m)) + O(nLog(n)) + O(i) = O(mLog(m)) if m > n
I have used library functions here. But if you want you can the write the functions using the same idea.
public class PostivieAsendingNegativeDesending implements Comparator<Integer> {
public static void main(String args[]) {
int fullList[] = {5, 4, 3, 2, 1, -3, -2, -30};
ArrayList<Integer> subList = new ArrayList<>();
ArrayList<Integer> subList2 = new ArrayList<>();
for (int i = 0; i < fullList.length; i++) {
if (fullList[i] < 0) {
subList2.add((fullList[i]));
} else {
subList.add(fullList[i]);
}
}
Collections.sort(subList);
Collections.sort(subList2, new PostivieAsendingNegativeDesending());
subList.addAll(subList2);
for (int i = 0; i < subList.size(); i++) {
System.out.print(subList.get(i) + " ");
}
System.out.println("");
}
#Override
public int compare(Integer n1, Integer n2) {
return n2 - n1;
}
}
This will do the trick which uses only basic loops
public static void main(String[] args) {
int a[] = { 5, 4, 3, 2, 1, -3, -2, -30 };
int length = a.length - 1;
int pos = 0, neg = 0;
// find total count of positive and negative numbers
for (int i = 0; i <= length; i++) {
if (a[i] < 0)
neg++;
else
pos++;
}
// initialize the arrays based on 'pos' and 'neg'
int posArr[] = new int[pos];
int negArr[] = new int[neg];
// store pos and neg values in the arrays
int countPos = 0, countNeg = 0;
for (int i = 0; i <= length; i++) {
if (a[i] < 0) {
negArr[countNeg] = a[i];
countNeg++;
} else {
posArr[countPos] = a[i];
countPos++;
}
}
// sort positive numbers
for (int i = 0; i < posArr.length - 1; i++) {
for (int j = 0; j < posArr.length - 1 - i; j++) {
if (posArr[j] > posArr[j + 1]) {
int swap = posArr[j];
posArr[j] = posArr[j + 1];
posArr[j + 1] = swap;
}
}
}
// sort negative numbers
for (int i = 0; i < negArr.length - 1; i++) {
for (int j = 0; j < negArr.length - 1 - i; j++) {
if (negArr[j] < negArr[j + 1]) {
int swap = negArr[j];
negArr[j] = negArr[j + 1];
negArr[j + 1] = swap;
}
}
}
// 1. print out posArr[] and then negArr[]
// or
// 2. merge them into another array and print
}
Logic is explained below :
Find total count of positive and negative numbers.
Create and store the positive and negative values in the respective arrays.
Sort positive array in ascending order.
Sort negative array in descending order.
Print out positive array followed by the negative array OR merge them into another and print.
I suggest another approach. You should try to formulate the rules to which the exact comparison must adhere.
Your requirement seem to have the following rules:
Positive numbers always come before negative numbers.
Positive numbers are ordered in ascending order.
Negative numbers are ordered in descending order. Yes, I said descending. Since higher numbers come before lower numbers, i.e. −2 is greater than −7.
Warning: you are using a nested for loop, which means that the process time will grow exponentially if the array becomes larger. The good news is: you don't need to nest a for loop into another for loop. I suggest writing a Comparator instead:
// The contract of Comparator's only method 'compare(i, j)' is that you
// return a negative value if i < j, a positive (nonzero) value if i > j and
// 0 if they are equal.
final Comparator<Integer> c = (i, j) -> { // I'm using a lambda expression,
// see footnote
// If i is positive and j is negative, then i must come first
if (i >= 0 && j < 0) {
return -1;
}
// If i is negative and j is positive, then j must come first
else if (i < 0 && j >= 0) {
return 1;
}
// Else, we can just subtract i from j or j from i, depending of whether
// i is negative or positive
else {
return (i < 0 ? j - i : i - j);
}
}
Your code could look like this:
int[] a = { 5, 4, 3, 2, 1, -3, -2, -30 };
int[] yourSortedIntArray = Arrays.stream(a)
.boxed()
.sorted(c) // Your Comparator, could also added inline, like
// .sorted((i, j) -> { ... })
.mapToInt(i -> i)
.toArray();
Lambda expressions are a new concept from Java 8. The Java Tutorials provide some valuable information.

How I can print largest sum in this Program?

package Message;
public class Example_R {
public static void main (String args[])
int n=1;
int input[]={1, 2, 1, 3, 4};
for (int j=0; j<=4; j++) {
int Add = 0;
for (int i=0; i<=4; i++) {
if (input[j] !=input[i]) {
Add+=input[i];
}
}
System.out.println(Add);
}
}
}
Output of This program is: 9 9 9 8 7 sum of all the other elements in the array that are not equal to the element.
Now I want to extend the program so I can print the Largest sum of any of it's element, (In this case 9 is the largest sum.) Do you have any suggestions? For this assignment I am restricted from using additional array, hashmap etc. not allowed. Arrays.sort(..)
Hint: use a variable that is holding "the largest sum reached so far". You will update it very time you compute a new sum.
You will need to find "how and when do I initialize this variable ?" and "how do I update it ?"
You probably want to create a separate method that you pass your "input[]" array to (left as an exercise). However when considering problems like this, first just consider how you would do it in english (or whatever your native language is). Write down that strategy (an "algorithm") and then implement that in Java.
public class Example_R {
public static void main(String args[]) {
int input[] = { 1, 2, 1, 3, 4 };
int largestSum = 0;
int currentSum;
for (int j = 0; j < input.length; j++) {
currentSum = 0;
for (int i = 0; i < input.length; i++) {
if (input[j] != input[i]) {
currentSum += input[i];
}
}
System.out.println("Sum of all values not equal to " + input[j]
+ " is: " + currentSum);
if (j == 0) {
largestSum = currentSum;
} else {
if (largestSum < currentSum) {
largestSum = currentSum;
}
}
}
System.out.println("The largest overall sum was " + largestSum);
}
}
You'll need a temporary variable to save the current highest number.
int temp = intArray[0]
for(int i : intArray)
{
if(i > temp)
temp = i;
}
Try this:
int n = 1,sum=0;
int[] input = { 1, 2, 1, 3, 4 };
for (int j = 0; j <= 4; j++){
int Add = 0;
for (int i = 0; i <= 4; i++){
if (input[j] != input[i])
Add += input[i];
}
if (sum < Add)
sum = Add;
}
After completing the second loop every time,the "sum" was updated if it is less than the current "add" value.
You can use variables of type Comparable and use the compareTo() method.
one.compareTo(two) will return > 0 if one > two
one.compareTo(two) will return < 0 if one < two
one.compareTo(two) will return 0 if one and two are equal
Go through the array, compare the current index with the previous index, and update a variable that holds the currentLargest value.

Comparing Arrays in Java for a Game

I wondering if someone could help me, I have a game where the computer generates a random 4 digit code, each digit ranging from 0-5. Then the user guesses this code and the computer returns an array that i print out to a string. The array should contain a 6 for every number in the guess that is the correct number in the correct place, a 7 for each number in the guess that is a correct number but wrong spot for it, and finally a 5 for any completely incorrect numbers.
Example,, if the code is: 0143
and the user's guess is: 0451
the array should be: 6775
This is because the 0 is completely correct, the 1 and 4 are in the code, but were guessed in the wrong spot, and the 5 is completely incorrect. Also each digit is in a separate part of the arrays.
This is what I have so far:
for (int i = 0; i < 4; i++) {
if (combo[i] == guess[i]) {
Pegs[peg] = 6;
peg++;
}
}
for (int i = 0; i < 4; i++) {
for (int x = 0; x < 4; x++) {
if (guess[i] == combo[x] && guess[i] != combo[i]) {
Pegs[peg] = 7;
peg++;
}
}
}
for (int i = 0; i < 4; i++) {
if (Pegs[i] == 0) {
Pegs[i] = 5;
}
}
The array guess stores the users guess, the array combo is the correct code, Pegs[] is where the compared array is stored, and the int peg just says where to store the value in the array. The problem with this is it doesn't always return the array correctly to what it to do.
With the other methods, you will get into troubles if you have a scenario where
int[] combot = new int[] {0, 1, 1, 3};
int[] guess = new int[] {0, 4, 5, 1};
as you'll get an incorrect [6, 7, 7, 5] instead of the correct [6, 7, 5, 5] because you'll count your last guess 1 in double.
By using two flags array, one for the exact matches and one for the misplaced guess a single flag array, you can achieve much better and accurate results :
** Edited ** I reverted it back because I have found that for combo = [0, 1, 1, 3] and guess = [3, 0, 1, 5], it was giving an incorrect response.
public int[] computeGuess(int[] combo, int[] guess) {
int[] result = new int[4];
Arrays.fill(result, 5); // incorrect values for all!
boolean[] exactMatches = new boolean[4]; // all initially set to false
boolean[] misplaced = new boolean[4];
for (int i = 0; i < 4; i++) {
if (combo[i] == guess[i]) {
exactMatches[i] = true;
misplaced[i] = false; // make sure we don't use this as misplaced
} else {
for (int j = 0; j < 4; j++) {
if (i != j && combo[i] == guess[j] && !exactMatches[j] && !misplaced[j]) {
misplaced[j] = true;
break;
}
}
}
}
int i = 0;
for (boolean b : exactMatches) {
if (b) {
result[i++] = 6;
}
}
for (boolean b : misplaced) {
if (b) {
result[i++] = 7;
}
}
return result;
}
To compare the array you need only the first loop and the inner loop should be executed only if the numbers at the same position are not equal:
for(int i = 0; i < 4; i++) {
Pegs[i]=5;
if(combo[i] == guess[i]) {
Pegs[i] = 6;
guess[i]= -1;
}
}
for(int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if(combo[i] == guess[j]) {
Pegs[i]=7;
guess[j]= -1;
break;
}
}
}
...

Categories

Resources