Related
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;
}
I have a given matrix called m and its dimensions are n by n and it contains whole numbers. I need to copy the numbers that appear just once to a new array called a.
I think the logic would be to have a for loop for each number in the matrix and compare it to every other number, but I don't know how to actually do that with code.
I can only use loops (no maps or such) and this is what I've come up with:
public static void Page111Ex14(int[][] m) {
int previous = 0, h = 0;
int[] a = new int[m.length*m[0].length];
for (int i = 0; i < m.length; i++) {
for (int j = 0; j < m[0].length; j++) {
previous = m[i][j];
if (m[i][j] != previous) {
a[h] = m[i][j];
h++;
}
}
}
It's probably not correct though.
Loop through it again to see if there's any repeated one. Assuming you can use labels, the answer might look a bit like that:
public static int[] getSingleInstanceArrayFromMatrix(int[][] m) {
int[] a = new int[m.length * m[0].length];
// Main loop.
for (int x = 0; x < m.length; x++) {
for (int y = 0; y < m[0].length; y++) {
// Gets the current number in the matrix.
int currentNumber = m[x][y];
// Boolean to check if the variable appears more than once.
boolean isSingle = true;
// Looping again through the array.
checkLoop:
for (int i = 0; i < m.length; i++) {
for (int j = 0; j < m[0].length; j++) {
// Assuring we are not talking about the same number in the same matrix position.
if (i != x || j != y) {
// If it is equal to our current number, we can update the variable and break.
if (m[i][j] == currentNumber) {
isSingle = false;
break checkLoop;
}
}
}
}
if (isSingle) {
a[(x * m.length) + y] = currentNumber;
}
}
}
return a;
}
Not sure if it's the most efficient, but I think it will work. It's somewhat hard to form your final array without the help of Lists or such. Since the unassigned values will default to 0, any actual zero (i.e. it's "supposed" to be there based on the matrix) will be undetected if you look up the returned array. But if there's such limitations I imagine that it's not crucially important.
This is one of those problems you can just throw a HashMap at and it just does your job for you. You traverse the 2d array, use a HashMap to store each element with its occurence, then traverse the HashMap and add all elements with occurence 1 to a list. Then convert this list to an array, which is what you're required to return.
This has O(n*n) complexity, where n is one dimension of the square matrix m.
import java.util.*;
import java.io.*;
class GetSingleOccurence
{
static int[] singleOccurence(int[][] m)
{
// work with a list so that we can append to it
List<Integer> aList = new ArrayList<Integer>();
HashMap<Integer, Integer> hm = new HashMap<>();
for (int row = 0; row < m.length; row++) {
for (int col = 0; col < m[row].length; col++) {
if (hm.containsKey(m[row][col]))
hm.put(m[row][col], 1 + hm.get(m[row][col]));
else
hm.put(m[row][col], 1);
}
}
for (Map.Entry entry : hm.entrySet())
{
if (Integer.parseInt(String.valueOf(entry.getValue())) == 1)
a.add(Integer.parseInt(String.valueOf(entry.getKey())));
}
// return a as an array
return a.toArray(new int[a.size()]);
}
public static void main(String args[])
{
// A 2D may of integers with some duplicates
int[][] m = { { 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
{ 11, 12, 12, 14, 15 },
{ 16, 17, 18, 18, 20 },
{ 21, 22, 23, 24, 25 } };
a = singleOccurence(m);
}
}
It may be better to use a boolean array boolean[] dups to track duplicated numbers, so during the first pass this intermediate array is populated and the number of singles is counted.
Then create the resulting array of appropriate size, and if this array is not empty, in the second iteration over the dups copy the values marked as singles to the resulting array.
public static int[] getSingles(int[][] arr) {
int n = arr.length;
int m = arr[0].length;
boolean[] dups = new boolean[n * m];
int singles = 0;
for (int i = 0; i < dups.length; i++) {
if (dups[i]) continue; // skip the value known to be a duplicate
int curr = arr[i / m][i % m];
boolean dup = false;
for (int j = i + 1; j < dups.length; j++) {
if (curr == arr[j / m][j % m]) {
dup = true;
dups[j] = true;
}
}
if (dup) {
dups[i] = true;
} else {
singles++;
}
}
// debugging log
System.out.println("singles = " + singles + "; " + Arrays.toString(dups));
int[] res = new int[singles];
if (singles > 0) {
for (int i = 0, j = 0; i < dups.length; i++) {
if (!dups[i]) {
res[j++] = arr[i / m][i % m];
}
}
}
return res;
}
Test:
int[][] mat = {
{2, 2, 3, 3},
{4, 2, 0, 3},
{5, 4, 2, 1}
};
System.out.println(Arrays.toString(getSingles(mat)));
Output(including debugging log):
singles = 3; [true, true, true, true, true, true, false, true, false, true, true, false]
[0, 5, 1]
Your use of previous is merely an idea on the horizon. Remove it, and fill the one dimensional a. Finding duplicates with two nested for-loops would require n4 steps. However if you sort the array a, - order the values - which costs n² log n², you can find duplicates much faster.
Arrays.sort(a);
int previous = a[0];
for (int h = 1; h < a.length; ++h) {
if (a[h] == previous)...
previous = a[h];
...
It almost looks like this solution was already treated in class.
It doesn't look good:
previous = m[i][j];
if (m[i][j] != previous) {
a[h] = m[i][j];
h++;
}
you assigned m[i][j] to previous and then you check if if (m[i][j] != previous)?
Are there any limitations in the task as to the range from which the numbers can come from?
I have an array:
private static int[] array = {5, 2, 1, 6, 3, 7, 8, 4};
I'm trying to split it into a two-dimensional array with x amount of chunks, where all of the chunks have an equal length (in my case, 2), then assign each value of the original array to a corresponding index within the array. It would then increment the index of the chunk number and reset the index iterating through the individual arrays hit the length of one.
Problem is, the code I wrote to perform all that isn't outputting anything:
public class Debug
{
private static int[] array = {5, 2, 1, 6, 3, 7, 8, 4};
private static void chunkArray(int chunkSize)
{
int chunkNumIndex = 0;
int chunkIndex = 0;
int numOfChunks = (int)Math.ceil((double)array.length / chunkSize);
int[][] twoDimensionalArray = new int[numOfChunks][chunkSize];
for (int i = 0; i < array.length; i++)
{
twoDimensionalArray[chunkNumIndex][chunkIndex] = array[i];
chunkIndex++;
while(chunkNumIndex < numOfChunks)
{
if (chunkIndex == chunkSize)
{
chunkNumIndex++;
chunkIndex = 0;
}
}
}
for(int i = 0; i < chunkNumIndex; i++)
{
for(int j = 0; j < chunkIndex; j++)
{
System.out.printf("%5d ", twoDimensionalArray[i][j]);
}
System.out.println();
}
}
public static void main(String args[])
{
chunkArray(2);
}
}
Could anyone be of assistance in debugging my program?
The problem is that you have an unnecessary while(chunkNumIndex < numOfChunks) which makes no sense. The if statement is sufficient to iterate your variables correctly:
for (int i = 0; i < array.length; i++) {
twoDimensionalArray[chunkNumIndex][chunkIndex] = array[i];
chunkIndex++;
if (chunkIndex == chunkSize) {
chunkNumIndex++;
chunkIndex = 0;
}
}
Also, remember that the values of chunkNumIndex and chunkIndex are dynamic, so for the last for loops, use twoDimensionalArray.length and twoDimensionalArray[0].length instead:
for(int i = 0; i < twoDimensionalArray.length; i++) {
for(int j = 0; j < twoDimensionalArray[0].length; j++) {
System.out.printf("%5d ", twoDimensionalArray[i][j]);
}
}
You're making this unnecessarily hard, there is no need to keep counters for chunkIndex and chunkNumIndex, we can just div and mod i.
int numOfChunks = (array.length / chunkSize) + (array.length % chunkSize == 0 ? 0 : 1);
int[][] twoDimensionalArray = new int[numOfChunks][chunkSize];
for (int i = 0; i < array.length; i++) {
twoDimensionalArray[i / chunkSize][i % chunkSize] = array[i];
}
Something like this should already do the job.
This is my first post, hope it complies with posting guidelines of the site.
First of all a generic thanks to all the community: reading you from some months and learned a lot :o)
Premise: I'm a first years student of IT.
Here's the question: I'm looking for an efficient way to count the number of unique pairs (numbers that appear exactly twice) in a given positive int array (that's all I know), e.g. if:
int[] arr = {1,4,7,1,5,7,4,1,5};
the number of unique pairs in arr is 3 (4,5,7).
I have some difficulties in... evaluating the efficiency of my proposals let's say.
Here's the first code I did:
int numCouples( int[] v ) {
int res = 0;
int count = 0;
for (int i = 0 ; i < v.length; i++){
count = 0;
for (int j = 0; j < v.length; j++){
if (i != j && v[i] == v[j]){
count++;
}
}
if (count == 1){
res++;
}
}
return res/2;
}
This shoudn't be good cause it checks the whole given array as many times as the number of elements in the given array... correct me if I'm wrong.
This is my second code:
int numCouples( int[] v) {
int n = 0;
int res = 0;
for (int i = 0; i < v.length; i++){
if (v[i] > n){
n = v[i];
}
}
int[] a = new int [n];
for (int i = 0; i < v.length; i++){
a[v[i]-1]++;
}
for (int i = 0; i < a.length; i++){
if (a[i] == 2){
res++;
}
}
return res;
}
I guess this should be better than the first one since it checks only 2 times the given array and 1 time the n array, when n is the max value of the given array. May be not so good if n is quite big I guess...
Well, 2 questions:
am I understanding good how to "measure" the efficiency of the code?
there's a better way to count the number of unique pairs in a given array?
EDIT:
Damn I've just posted and I'm already swamped by answers! Thanks! I'll study each one with care, for the time being I say I don't get those involving HashMap: out of my knowledge yet (hence thanks again for the insight:o) )
public static void main(String[] args) {
int[] arr = { 1, 4, 7, 1, 5, 7, 4, 1, 5 };
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < arr.length; i++) {
Integer count = map.get(arr[i]);
if (count == null)
map.put(arr[i], 1);
else
map.put(arr[i], count + 1);
}
int uniqueCount = 0;
for (Integer i : map.values())
if (i == 2)
uniqueCount++;
System.out.println(uniqueCount);
}
Well, here's another answer to your's 2 questions:
am I understanding good how to "measure" the efficiency of the code?
There are various ways to measure efficiency of the code. First of all, people distinguish between memory efficiency and time efficiency. The usual way to count all these values is to know, how efficient are the building blocks of your algorithm. Have a look at the wiki.
For instance, sorting using quicksort would need n*log(n) operations. Iterating through the array would need just n operations, where n is number of elements in the input.
there's a better way to count the number of unique pairs in a given array?
Here's another solution for you. The complixity of this one would be: O(n*log(n)+n), where O(...) is Big O notation.
import java.util.Arrays;
public class Ctest {
public static void main(String[] args) {
int[] a = new int[] { 1, 4, 7, 1, 7, 4, 1, 5, 5, 8 };
System.out.println("RES: " + uniquePairs(a));
}
public static int uniquePairs(int[] a) {
Arrays.sort(a);
// now we have: [1, 1, 1, 4, 4, 5, 5, 7, 7]
int res = 0;
int len = a.length;
int i = 0;
while (i < len) {
// take first number
int num = a[i];
int c = 1;
i++;
// count all duplicates
while(i < len && a[i] == num) {
c++;
i++;
}
System.out.println("Number: " + num + "\tCount: "+c);
// if we spotted number just 2 times, increment result
if (c == 2) {
res++;
}
}
return res;
}
}
public static void main(String[] args) {
int[] arr = {1,4,7,1,7,4,1,5};
Map<Integer, Integer> counts = new HashMap<Integer,Integer>();
int count = 0;
for(Integer num:arr){
Integer entry = counts.get(num);
if(entry == null){
counts.put(num, 1);
}else if(counts.get(num) == 1){
count++;
counts.put(num, counts.get(num) + 1);
}
}
System.out.println(count);
}
int [] a = new int [] {1, 4, 7, 1, 7, 4, 1, 5, 1, 1, 1, 1, 1, 1};
Arrays.sort (a);
int res = 0;
for (int l = a.length, i = 0; i < l - 1; i++)
{
int v = a [i];
int j = i + 1;
while (j < l && a [j] == v) j += 1;
if (j == i + 2) res += 1;
i = j - 1;
}
return res;
you can use HashMap for easy grouping. here is my code.
int[] arr = {1,1,1,1,1,1,4,7,1,7,4,1,5};
HashMap<Integer,Integer> asd = new HashMap<Integer, Integer>();
for(int i=0;i<arr.length;i++)
{
if(asd.get(arr[i]) == null)
{
asd.put(arr[i], 1);
}
else
{
asd.put(arr[i], asd.get(arr[i])+1);
}
}
//print out
for(int key:asd.keySet())
{
//get pair
int temp = asd.get(key)/2;
System.out.println(key+" have : "+temp+" pair");
}
added for checking the unique pair, you can delete the print out one
//unique pair
for(int key:asd.keySet())
{
if(asd.get(key) == 2)
{
System.out.println(key+" are a unique pair");
}
}
after some time another solution, which should work great.
public getCouplesCount(int [] arr) {
int i = 0, i2;
int len = arr.length;
int num = 0;
int curr;
int lastchecked = -1;
while (i < len-1) {
curr = arr[i];
i2 = i + 1;
while (i2 < len) {
if (curr == arr[i2] && arr[i2] != lastchecked) {
num++; // add 1 to number of pairs
lastchecked = curr;
i2++; // iterate to next
} else if (arr[i2] == lastchecked) {
// more than twice - swap last and update counter
if (curr == lastchecked) {
num--;
}
// swap with last
arr[i2] = arr[len-1];
len--;
} else {
i2++;
}
i++;
}
return num;
}
i am not shure if it works, but it is more effective than sorting the array first, or using hashmaps....
A Java8 parallel streamy version which uses a ConcurrentHashMap
int[] arr = {1,4,7,1,5,7,4,1,5};
Map<Integer,Long> map=Arrays.stream(arr).parallel().boxed().collect(Collectors.groupingBy(Function.identity(),
ConcurrentHashMap::new,Collectors.counting()));
map.values().removeIf(v->v!=2);
System.out.println(map.keySet().size());
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int arr[9] = {1,4,7,1,5,7,4,1,5}; // given array
int length=9; // this should be given
int count=0;
map<int,int> m;
for(int i=0;i<length;i++)
m[arr[i]]++;
cout<<"List of unique pairs : ";
for(auto it=m.begin();it!=m.end();it++)
if(it->second==2)
{
count++;
cout<<it->first<<" ";
}
cout<<"\nCount of unique pairs(appears exactly twice) : "<<count;
return 0;
}
OUTPUT :
List of unique pairs : 4 5 7
Count of unique pairs(appears exactly twice) : 3
Time Complexity : O(N) where N is the number of elements in array
Space Complexity : O(N) total no. of unique elements in array always <=N
var sampleArray = ['A','B','C','D','e','f','g'];
var count = 0;
for(var i=0; i<=sampleArray.length; i++) {
for(var j=i+1; j<sampleArray.length; j++) {
count++;
console.log(sampleArray[i] , sampleArray[j]);
}
}
console.log(count);
This is the simple way I tried.
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;
}
}
}
...