counting number of unique elements - java

Hi so I am supposed to count the number of unique elements after an array sort excluding duplicates but i'm getting the wrong output.
In in = new In(args[0]);
int[] whitelist = in.readAllInts();
Arrays.sort(whitelist);
int count = 0;
for (int i = 0; i < whitelist.length; i++) {
if (whitelist[i] == whitelist[count]) {
count++;
}
}
while (!StdIn.isEmpty()) {
int key = StdIn.readInt();
rank(key, whitelist);
}
System.out.println(count);
}
}
expected output: java InstrumentedBinarySearch tinyW.txt < tinyT.txt
65
got: 16
Did i count the number of duplicates or something?

int flag = 0;
int count = 0;
for (int i = 0; i < whitelist.length; i++) //Element to be checked for
{
for (int j=0; j< whitelist.length ; j++) //Loop that goes through the whole array
{
if (whitelist[i] == whitelist[j]) //checks if there are duplicates
{
flag++; // count
}
}
if( flag==1) //There should be only 1 instance of the element in the array and that is the element itself
{
System.out.println(whitelist[i]); //displays unique element
count++; // Keeps count
}
}

This algorithm counts how many different unique numbers there are in the array. A number appearing more than once will only count for 1. I am assuming this is what you mean, as opposed to "numbers which appear exactly once".
There is a more trivial way to do it, as proposed in another answer, but it requires a nested for-loop and therefore executes in quadratic complexity. My algorithm below attempts to solve the problem in linear time proportional to the array size.
int uniquesFound = 0;
// Assume that array is sorted, so duplicates would be next to another.
// If we find duplicates, such as 12223, we will only count its last instance (i.e. the last '2')
for (int i = 0; i < whitelist.length; i++) {
// If we are at the last element, we know we can count it
if (i != whitelist.length - 1) {
if (whitelist[i] != whitelist[i+1]) {
uniquesFound++;
}
else {
// Nothing! If they are the same, move to the next step element
}
} else {
uniquesFound++;
}
}
For instance, given the array:
{1,2,3} this will yield 3 because there are 3 unique numbers
{1,2,3,3,3,4,4,4,5} this will yield 5 because there are still 5 unique numbers

First let's take a look at your loop:
for (int i = 0; i < whitelist.length; i++) {
if (whitelist[i] == whitelist[count]) {
count++;
}
}
You should be comparing consecutive elements in the list, like whitelist[0] == whitelist[1]?, whitelist[1] == whitelist[2]?, whitelist[3] == whitelist[4]?, etc. Doing whitelist[i] == whitelist[count] makes no sense in this context.
Now you have two options:
a. Increment your counter when you find two consecutive elements that are equal and subtract the result from the total size of the array:
for (int i = 0; i < whitelist.length - 1; i++) {
if (whitelist[i] == whitelist[i + 1]) {
count++;
}
}
int result = whitelist.length - count;
b. Change the condition to count the transitions between consecutive elements that are not equal. Since you are counting the number of transitions, you need to add 1 to count in the end to get the number of unique elements in the array:
for (int i = 0; i < whitelist.length - 1; i++) {
if (whitelist[i] != whitelist[i + 1]) {
count++;
}
}
int result = count + 1;
Note that, in both cases, we loop only until whitelist.length - 1, so that whitelist[i + 1] does not go out of bounds.

Related

Verifying the time complexity of selection sort by counting the number of comparisons

I'm trying to verify that selection sort is O(n^2) by counting the number of times numbers are being compared in my array. I'm using an array of 20 numbers so I know I should be getting somewhere around 400, but with the current placement of my counting variable I'm only getting around 200 comparisons being counted. Here is the code for the selection sort I am using:
public static void selectionSort(final int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minElementIndex = i;
for (int j = i + 1; j < arr.length; j++) {
swapCount++;
if (arr[minElementIndex] > arr[j])
{
minElementIndex = j;
}
}
if (minElementIndex != i) {
int temp = arr[i];
arr[i] = arr[minElementIndex];
arr[minElementIndex] = temp;
}
}
}
The swapCount variable is being used to track the comparisons and I've tried moving it around everywhere I could think of, but I can't get a count nearly as high as I'm expecting when I print the total swapCount at the end. Where exactly in the code should swapCount be to track all the comparisons?

Summing up the outer elements in a 2D array of integers in Java?

One of the questions from my exam asked to write some code to compute the sum of the outer int elements of a 2D array. Length of rows and length of columns aren't necessarily equal.
[EDIT] Corner values cannot be added more than once.
I came up with this code and it works, but I'd like to know if there are more efficient ways to achieve the same results. Thanks.
for(int i = 0; i < in.length; i ++) {
for(int j = 0; j < in[i].length; j++) {
if(i == 0 || i == in.length - 1) {
sum += in[i][j];
}
else {
sum += in[i][in[i].length - 1 ] + in[i][0];
break;
}
}
}
If I understand your question, then you could first extract a method to add the elements of one array like
public static int sumArray(int[] in) {
int sum = 0;
for (int val : in) {
sum += val;
}
return sum;
}
Then you can add the elements on the first and last rows like
int sum = sumArray(in[0]) + sumArray(in[in.length - 1]);
And then the outer elements from the other rows with an additional (non-nested) loop like
for (int i = 1; i < in.length - 1; i++) {
sum += in[i][0] + in[i][in[i].length - 1];
}
Or, in Java 8+, you might eliminate the extra method and the explicit loop and do it with one statement like
int sum = IntStream.of(in[0]).sum() //
+ IntStream.of(in[in.length - 1]).sum() //
+ IntStream.range(1, in.length - 1).map(i -> {
return in[i][0] + in[i][in[i].length - 1];
}).sum();
Yes you can do it more efficiently.
int row = in.length;
int column = in[0].length;//not sure of this syntax but trying to get the column size
int sum = 0;
for(int j=0;j<column;j++)
{
sum+=in[0][j]+in[row-1][j];
}
for(int j=1;j<row-1;j++)
{
sum+=in[j][0]+in[j][column-1];
}
Your solution is O(mn) and the loop iterates through unnecessary indexes.

Comparing two arrays. Wrong return value (1)

I made this method that compares the numbers of two arrays and then returns how many numbers are equal to each other, but no matter how many numbers are equal, the method returns the value 1 every time.
(both arrays are the same length).
public static void main(String[] args) {
int a [] = {1, 4, 6, 7, 8, 10, 13};
int b [] = {1, 2, 3, 4, 5, 6, 7};
equal(a,b);
}
public static int equal(int[] a, int[] b){
int j = 0;
for(int i = 0; i< a.length-1;i++){
if(a[i] == b[i]){
j++;
}
}
System.out.println(j);
return j;
}
Your code is finding the number that are equal at the same index.
There are several ways you can find the size of the intersection.
A simple but O(m*n) implementation would be to iterate over all elements of b for each element of a.
If the arrays are sorted, you could use separate indexes for the two arrays, advancing each when it can no longer match. This would be O(m+n). (If they're not sorted, you could sort them first, for a cost of O(m log m + n log n ).
If each array has no duplicate members, another way is to compute the size of the intersection is from the size of the set difference. An example of this is at http://ideone.com/6vLAfn. The key part is to convert each array to a set, and determine how many members are in common by removing one set from another.
int aSizeBefore = setA.size();
setA.removeAll( setB );
int aSizeAfter = setA.size();
return aSizeBefore - aSizeAfter;
You should use a nested for loop if you want to check if any single number in array a is also in array b.
e.g.
int numMatches = 0;
for (int i = 0; i < a.length; ++i)
{
for (int j = 0; j < b.length; ++j)
{
if (a[i] == b[j])
++numMatches; //Naive, as obviously if the same number appears twice in a it'll get counted twice each time it appears in b.
}
}
The current code just checks the elements at the same index match i.e
1 == 1 // Yes, increment j
4 == 2 // Nope
6 == 3 // Nope
7 == 4 // Nope
8 == 5 // Nope
10 == 6 // Nope
13 == 7 // Nope
Elements with same values might be in different indexes. You can write as following, assuming the arrays are sorted:
public static int equal(int[] a, int[] b) {
int count = 0;
for(int i = 0; i < a.length - 1; i++) {
for(int j = 0; i < b.length - 1; j++) {
if (a[j] < b[j]) {
// we came to the part where all elements in b are bigger
// than our selected element in a
break;
}
else if (a[j] == b[j]) {
count++;
}
}
}
System.out.println(count);
return count;
}
If you can't guarantee that the arrays are sorted, you can remove the if-block and remove the else-if's else from the loop.
If you want to know how many numbers are present in both arrays and there is a guarantee that they are ordered, you should try the following:
public static int equal(int[] a, int[] b) {
int j, result = 0;
int lastFound = 0;
for (int i = 0; i < a.length - 1; i++) {
for (j = lastFound; j < b.length; j++) {
if (a[i] == b[j]) {
result++;
lastFound = j;
break;
} else {
if (a[i] < b[j]) break;
}
}
}
return result;
}
Using the variable lastFound will speed your loops, but it is only helpful if the arrays are ordered, as your example indicates.

Array of 20 rolls of one die in java

I'm working on an exercise that requires that I print 20 rolls of a die out and group repeated values in parentheses. My code below follows the pseudocode the book I'm reading says to use. I am able to group the repeated values in parentheses but the next exercise requires that I group the values that are repeated the most in parentheses.
For example:
(333)51314121(22)326(55)14
would be:
(333)51314121223265514
EDIT: If there is more than one largest group of repeated values only the first is to be grouped in parentheses.
How can I accomplish this? Many thanks in advance for any help on this.
public void run() {
Random generator = new Random();
ArrayList<Integer> a = new ArrayList<Integer>();
for (int i = 0; i < 21; i++) {
int die = generator.nextInt(6)+ 1;
a.add(die);
}
for (int j = 0; j < a.size() - 1; j++) {
if (inRun) {
if (a.get(j) != a.get(j - 1)) {
System.out.print(")");
inRun = false;
}
}
else {
if (a.get(j) == a.get(j + 1)) {
System.out.print("(");
inRun = true;
}
}
System.out.print(a.get(j));
}
if (inRun) {
System.out.print(")");
}
}
You don't really need a data structure other than an ordinary array.
You can make it O(n) by checking while inserting:
If the added number equals the previous, you increment the sequence count - if not, you reset the count.
When you increment a sequence count, check if it is bigger than the already stored max sequence count length - if it is bigger, the current sequence count becomes the max sequence count.
Check the code - some comments there to help understanding (run demo online here):
public void run() {
Random generator = new Random();
int[] a = new int[20];
int biggerSequence = 1; // starts pointing to the first char
int biggerSequenceEndIndex = 1; // starts pointing to the first char
int currentSequence = 1;
int previous = -1;
for (int i = 0; i < 20; i++) {
int die = generator.nextInt(6)+ 1;
a[i] = die;
if (die == previous) { // if inserted equals previous
currentSequence++; // increment sequence
if (currentSequence > biggerSequence) { // if it is bigger than max
biggerSequence = currentSequence; // max becomes it
biggerSequenceEndIndex = i+1;
}
} else {
previous = die;
currentSequence = 1; // reset the count
}
}
for (int i = 0; i < a.length; i++) {
if (i == biggerSequenceEndIndex-biggerSequence) { System.out.print("("); }
System.out.print(a[i]);
if (i+1 == biggerSequenceEndIndex) { System.out.print(")"); }
}
}
Example outputs:
(1)2345678901234567890
(11)345678901234567890
1(22)45678901234567890
1(22)45578901234567890
123456789012345678(99)
54(3333)43514564513551
You need to make multiple passes over the array. Go through it once and tally up how long all the runs are. Then decide what the maximum run length is. Finally, go back and print out the array, putting parentheses around runs of the maximum length.
Try something like this (exact implementation left to you):
runContents = a list containing the first random number
runLength = [1], i.e. a one element list with the number 1 in it
maxLength = 1
for each subsequent random number you want to consider {
if the last element of runContents == the next random number {
add 1 to the last element of runLength
} else {
if maxLength < the last element of runLength {
maxLength = the last element of runLength
}
append the random number to runContents
append a 1 to runLength
}
}
i = 0
while i < length(runContents) {
if runLength[i] == maxLength {
print runLength[i] copies of runContents[i] surrounded by parens
} else {
print runLength[i] copies of runContents[i]
}
}
Just try storing the number of repeated values starting at any given index. Something like:
public void run(){
Random generator = new Random();
ArrayList<Integer> a = new ArrayList<Integer>();
for (int i = 0; i < 21; i++) {//Generate your numbers
int die = generator.nextInt(6)+ 1;
a.add(die);
}
//store the number of repeats by index. (index is key, # of repeats is key)
HashMap<Integer, Integer> repeats = new HashMap<Integer, Integer>();
//This will find store the number of repeated numbers starting at any given index.
int index = 0;
repeats.put(index, 1);
for(int i = 1; i < a.size(); i++){
if(a.get(i) == a.get(index)){//Repeated values occurring
repeats.put(index, repeats.get(index) + 1);
} else {//End of a repeated sequence (even if that sequence was only 1 number long)
repeats.put(i, 1);
index = i;
}
}
//Find the index at which the maximum number of repeats occurs
int max = 0;
int startIndex = 0;
for(Integer i : repeats.keySet()){
//If the number of repeats is bigger than anything seen before
if(repeats.get(i) > max){
//Store the number of repeats and the index at which they start
max = repeats.get(i);
startIndex = i;
}
}
//print everything out
for(int i = 0; i < a.size(); i++){
if(i == startIndex)//Prints the open parenthesis before the repeats start
System.out.print("(");
System.out.print(a.get(i)); //Prints the number
if(i == startIndex + max)
System.out.print(")");//Prints the close parenthesis after the repeats end
}
}
Note that this algorithm assumes that there is only 1 repeated sequence of the maximum size. Should there be multiple that you want to keep, you'll have to store all indexes in another list. But that's a minor fix to the solution that would look like so:
ArrayList<Integer> startIndeces = new ArrayList<Integer>();
int max = 0;
for(Integer i : repeats.keySet()){
//If the number of repeats is bigger than anything seen before
if(repeats.get(i) > max){
//Store the number of repeats and the index at which they start
max = repeats.get(i);
startIndeces = new ArrayList<Integer>();
startIndeces.add(i);
} else if(repeats.get(i) == max)
startIndeces.add(i);
}
Otherwise the algorithm stores the first instance of the longest sequence.

How do I sort numbers from an array into two different arrays in java?

I have to create a program that takes an array of both even and odd numbers and puts all the even numbers into one array and all the odd numbers into another. I used a for loop to cycle through all the numbers and determine if they are even or odd, but the problem I'm having is that since the numbers in the original array are random, I don't know the size of either the even or the odd array and therefore can't figure out how to assign numbers in the original array to the even/odd arrays without having a bunch of spots left over, or not having enough spots for all the numbers. Any ideas?
Try using an ArrayList. You can use
num % 2 == 0
to see if num is even or odd. If it does == 0 then it is even, else it is odd.
List<Integer> odds = new ArrayList();
List<Integer> evens = new ArrayList();
for (int i = 0; i< array.length; i++) {
if (array[i] % 2 == 0) {
evens.add(array[i]);
}
else {
odds.add(array[i]);
}
}
to convert the ArrayLists back to arrays you can do
int[] evn = evens.toArray(new Integer[evens.size()]);
(Note: untested code so there could be a few typos)
EDIT:
If you are not allowed to use ArrayLists then consider the following that just uses Arrays. It's not as efficient as it has to do two passes of the original array
int oddSize = 0;
int evenSize = 0;
for (int i = 0; i< array.length; i++) {
if (array[i] % 2 == 0) {
evenSize++;
}
else {
oddSize++;
}
}
Integer[] oddArray = new Integer[oddSize];
Integer[] evenArray = new Integer[evenSize];
int evenIdx = 0;
int oddIdx = 0;
for (int i = 0; i< array.length; i++) {
if (array[i] % 2 == 0) {
evenArray[evenIdx++] = array[i];
}
else {
oddArray[oddIdx++] = array[i];
}
}
You can do it without using arrays or any '%' Just a simple idea
input = new Scanner(System.in);
int x;
int y = 0; // Setting Y for 0 so when you add 2 to it always gives even
// numbers
int i = 1; // Setting X for 1 so when you add 2 to it always gives odd
// numbers
// So for example 0+2=2 / 2+2=4 / 4+2=6 etc..
System.out.print("Please input a number: ");
x = input.nextInt();
for (;;) { // infinite loop so it keeps on adding 2 until the number you
// input is = to one of y or i
if (x == y) {
System.out.print("The number is even ");
System.exit(0);
}
if (x == i) {
System.out.print("The number is odd ");
System.exit(0);
}
if (x < 0) {
System.out.print("Invald value");
System.exit(0);
}
y = y + 2;
i = i + 2;
}
}
Use a List instead. Then you don't need to declare the sizes in advance, they can grow dynamically.
You can always use the toArray() method on the List afterwards if you really need an array.
The above answers are correct and describe how people would normally implement this. But the description of your problem makes me think this is a class assignment of sorts where dynamic lists are probably unwelcome.
So here's an alternative.
Sort the array to be divided into two parts - of odd and of even numbers. Then count how many odd/even numbers there are and copy the values into two arrays.
Something like this:
static void insertionSort(final int[] arr) {
int i, j, newValue;
int oddity;
for (i = 1; i < arr.length; i++) {
newValue = arr[i];
j = i;
oddity = newValue % 2;
while (j > 0 && arr[j - 1] % 2 > oddity) {
arr[j] = arr[j - 1];
j--;
}
arr[j] = newValue;
}
}
public static void main(final String[] args) {
final int[] numbers = { 1, 3, 5, 2, 2 };
insertionSort(numbers);
int i = 0;
for (; i < numbers.length; i++) {
if (numbers[i] % 2 != 0) {
i--;
break;
}
}
final int[] evens = new int[i + 1];
final int[] odds = new int[numbers.length - i - 1];
if (evens.length != 0) {
System.arraycopy(numbers, 0, evens, 0, evens.length);
}
if (odds.length != 0) {
System.arraycopy(numbers, i + 1, odds, 0, odds.length);
}
for (int j = 0; j < evens.length; j++) {
System.out.print(evens[j]);
System.out.print(" ");
}
System.out.println();
for (int j = 0; j < odds.length; j++) {
System.out.print(odds[j]);
System.out.print(" ");
}
}
Iterate through your source array twice. The first time through, count the number of odd and even values. From that, you'll know the size of the two destination arrays. Create them, and take a second pass through your source array, this time copying each value to its appropriate destination array.
I imagine two possibilities, if you can't use Lists, you can iterate twice to count the number of even and odd numbers and then build two arrays with that sizes and iterate again to distribute numbers in each array, but thissolution is slow and ugly.
I imagine another solution, using only one array, the same array that contains all the numbers. You can sort the array, for example set even numbers in the left side and odd numbers in the right side. Then you have one index with the position in the array with the separation ofthese two parts. In the same array, you have two subarrays with the numbers. Use a efficient sort algorithm of course.
Use following Code :
public class ArrayComparing {
Scanner console= new Scanner(System.in);
String[] names;
String[] temp;
int[] grade;
public static void main(String[] args) {
new ArrayComparing().getUserData();
}
private void getUserData() {
names = new String[3];
for(int i = 0; i < names.length; i++) {
System.out.print("Please Enter Student name: ");
names[i] =console.nextLine();
temp[i] = names[i];
}
grade = new int[3];
for(int i =0;i<grade.length;i++) {
System.out.print("Please Enter Student marks: ");
grade[i] =console.nextInt();
}
sortArray(names);
}
private void sortArray(String[] arrayToSort) {
Arrays.sort(arrayToSort);
getIndex(arrayToSort);
}
private void getIndex(String[] sortedArray) {
for(int x = 0; x < sortedArray.length; x++) {
for(int y = 0; y < names.length; y++) {
if(sortedArray[x].equals(temp[y])) {
System.out.println(sortedArray[x] + " " + grade[y]);
}
}
}
}
}

Categories

Resources