I am trying to solve this, but i don't know how...
Values[10] = {1,1,4,4,2,3,3,2,1,3}
to print:
{1,2,3,4} or {1,4,2,3} (not sorted, any order, but distinct)
I also need to count the number of times each number has occurred, both without sort, new arrays or boolean methods or other data structures, please advise as i am stuck.
Is there a simple method i can use to just print the unique values/ distinct values ?
It can be accomplished if your are willing to destroy your current array. and you assume that the array is either of type Integer (so nullable) or if not there is some bound such as all int are poistive so you can use -1.
for(int i = 0; i < values.length; i++){ //for entire array
Integer currVal = values[i]; // select current value
int count = 1; // and set count to 1
if(currVal != null){ // if value not seen
for( int j = i + 1; j < values.length; j++){ // for rest of array
if(values[j] == currVal){ // if same as current Value
values[j] = null; // mark as seen
count++; // and count it
}
}
System.out.print("Number : " + currVal + " Count : " + count + "\n");
//print information
}
// if seen skip.
}
In plain english, Go through the array in 2 loops, roughly O(n^2) time.
Go to index i. If index has not yet been seen (is not null) then go through the rest of array, mark any indexs with same value as seen (make it null) and increment count varable. At end of loop print value and count. If Index has be seen (is null) skip and go to next index. At end of both loops all values will be left null.
Input : Values[] = {1,1,4,4,2,3,3,2,1,3}
Output : Values[] = {1,null,4,null,2,3,null,null,null,null}
Number : 1 Count : 3
Number : 4 Count : 2
Number : 2 Count : 2
Number : 3 Count : 3
Edit: corrected my mistake in output, pointed out by commenters.
Another solution, without creating additional objects:
Arrays.sort(values);
for(int i = 0; i < values.length; i++) {
if (i == 0 || value[i] != value[i-1]) {
System.out.println(values[i]);
}
}
And the shortest solution I can think of:
Integer[] values = {1,1,4,4,2,3,3,2,1,3};
Set<Integer> set = new HashSet<Integer>();
set.addAll(Arrays.asList(values));
System.out.println(set);
Assuming the values are guaranteed to be integers, you could also do it by incrementing a check value, scan over the array, sum the number of that check value in the array, add it to an accumulator and loop while the accumulator < array.length.
Something like this (untested):
public void checkArray(int[] toCheck) {
int currentNum = 0;
int currentCount = 0;
int totalSeen = 0;
StringBuilder sb = new StringBuilder();
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for(int i=0; i<toCheck.length; i++) {
min = Math.min(toCheck[i], min);
max = Math.max(toCheck[i], max);
}
System.out.print("{ ");
for(currentNum = min; currentNum < max; currentNum++) {
for(int i=0; i<toCheck.length; i++) {
if(toCheck[i] == currentNum) currentCount++;
}
if(currentCount != 0) {
if(currentNum == min) System.out.print(currentCount + "(" +currentCount+ ")");
else System.out.print(", " + currentCount + " (" +currentCount+ ")");
}
totalSeen += currentCount;
currentCount = 0;
}
System.out.println(" }");
}
It should be noted that while this technically fulfills all your requirements, it will be far less efficient than gbtimmon's approach.
If your ints were {1,2,3,150000}, for example, it will needlessly spin over all the values between 4 and 149999.
Edit: added better limits from tbitof's suggestion.
Your question isn't quite clear to me, since it sounds like you want to do these things without creating any additional objects at all. But if it's just about not creating another array, you could use a Map<Integer, Integer>, where the key is the number from your original array, and the value is the count of times you've seen it. Then at the end you can look up the count for all numbers, and print out all the keys by using Map.keyset()
Edit: For example:
Map<Integer,Integer> counts = new HashMap<Integer, Integer>();
for( int i : values ) {
if( counts.containsKey(i) ) {
counts.put(i, counts.get(i) + 1);
} else {
counts.put(i, 1);
}
}
// get the set of unique keys
Set uniqueInts = counts.keyset();
Related
Hello all please check the problemHackerRank Problem Statement
This is my solution for the above problem(link)
static int migratoryBirds(List<Integer> arr) {
int ar[]=new int[arr.size()];
for(int i=0;i<arr.size();i++){
ar[i] = Collections.frequency(arr,arr.get(i));
// ar[i] = obj.occuranceOfElement(arr,arr.get(i));
}
int maxAt = 0;
for (int i = 0; i < ar.length; i++) {
maxAt = ar[i] > ar[maxAt] ? i : maxAt;
}
return arr.get(maxAt);
}
my code is unable to handle when the array size is bigger,example 17623 elements in array.
Terminated due to timeout
The problem is in the second for loop which iterates over the array and gives me the index of the largest number in the array.Is there any other way that I could increase the performance.
Your problem is in this part:
for(int i = 0; i < arr.size(); i++)
ar[i] = Collections.frequency(arr, arr.get(i));
This is O(N²): Collections.frequency() iterates over whole list to calculate frequency for only one element. Manually, you can iterate over the list to calculate frequencey for all elements.
Moreover, ther're only 5 birds, so you need only 5 length array.
static int migratoryBirds(int[] arr) {
int max = 1;
int[] freq = new int[6];
for (int val : arr)
freq[val]++;
for (int i = 2; i < freq.length; i++)
max = freq[i] > freq[max] ? i : max;
return max;
}
Your problem is the call to Colletions.frequency, which is an O(N) operation. When you call it from inside a loop it becomes O(N²) and that consumes all your time.
Also, are you sure which implmentation of List you receive? You call list.get(i) which might also be O(N) if the implementation is a LinkedList.
The target of this exercise is to calculate the frequency of each value in one pass over the input. You need a place where you store and increase the number of occurrences for each value and you need to store the largest value of the input.
You have also skipped over a crucial part of the specification. The input has limits which makes solving the problem easier than you now think.
Here's another one:
static int migratoryBirds(List<Integer> arr) {
int freq[]=new int[6];
for(int i=0;i<arr.size();i++){
++freq[arr.get(i)];
}
int maxAt = 1;
for (int i = 2; i < freq.length; i++) {
if (freq[i] > freq[maxAt]) {
maxAt = i;
}
}
return maxAt;
}
We can determine the type number of the most common bird in one loop. This has the time complexity O(n).
static int migratoryBirds(int[] arr) {
int highestFrequency = 0;
int highestFrequencyBirdType = 0;
int[] frequencies = new int[5]; // there are 5 bird types
for (int birdType : arr) {
int frequency = ++frequencies[birdType - 1];
if (frequency > highestFrequency) {
highestFrequency = frequency;
highestFrequencyBirdType = birdType;
} else if (frequency == highestFrequency && birdType < highestFrequencyBirdType) {
highestFrequencyBirdType = birdType;
}
}
return highestFrequencyBirdType;
}
For each element in the array arr we update the overall highestFrequency and are storing the corresponding value representing the highestFrequencyBirdType . If two different bird types have the highest frequency the lower type (with the smallest ID number) is set.
Some Background
Last week I did a problem in my textbook where It told me to generate 20 random numbers and then put brackets around successive numbers that are equal
Consider the following which my program outputs
697342(33)(666)(44)69(66)1(88)
What I need to do
The next problem was to basically get the longest sequence of these words and put brackets around them. If you have
1122345(6666)
Basically you need to put brackets around four 6's , since they occur most often.
I've finished all other problems in the chapter I am studying ( Arrays and ArrayLists), however I can't seem to figure this one out.
Here is the solution that I have made for putting brackets around successive numbers:
class Seq
{
private ArrayList<Integer> nums;
private Random randNum;
public Seq()
{
nums = new ArrayList<Integer>();
randNum = new Random();
}
public void fillArrList()
{
for (int i = 0 ; i < 20 ; i++)
{
int thisRandNum = randNum.nextInt(9)+1;
nums.add(thisRandNum);
}
}
public String toString() {
StringBuilder result = new StringBuilder();
boolean inRun = false;
for (int i = 0; i < nums.size(); i++) {
if (i < nums.size() - 1 && nums.get(i).equals(nums.get(i + 1))) {
if (!inRun) {
result.append("(");
}
result.append(nums.get(i));
inRun = true;
} else {
result.append(nums.get(i));
if (inRun) {
result.append(")");
}
inRun = false;
}
}
return result.toString();
}
}
My Thoughts
Iterate through the whole list. Make a count variable, that keeps track of how many numbers are successive of each other. I.e 22 would have a count of 2. 444 a count of 3
Next make an oldCount, which compares the current count to the oldCount. We only want to keep going if our new count is greater than oldCount
After that we need a way to get the starting index of the largest count variable, as well as the end.
Is my way of thinking correct? Because I'm having trouble updating the oldCount and count variable while comparing them, since there values constantly change. I'm not looking for the code, but rather some valuable hints.
My count is resetting like this
int startIndex, endIndex = 0;
int count = 0;
int oldCount = 0;
for(int i = 0 ; i < nums.size(); i++)
{
if(nums.get(i) == nums.get(i+1) && count >= oldCount)
{
count++;
}
oldCount = count;
}
Only after walking all elements you will know the longest subsequence.
11222333333444555
11222(333333)444555
Hence only after the loop you can insert both brackets.
So you have to maintain a local optimum: start index plus length or last index of optimum.
And then for every sequence the start index of the current sequence.
As asked:
The optimal state (sequence) and the current state are two things. One cannot in advance say that any current state is the final optimal state.
public String toString() {
// Begin with as "best" solution the empty sequence.
int startBest = 0; // Starting index
int lengthBest = 0; // Length of sequence
// Determine sequences:
int startCurrent = 0; // Starting index of most current/last sequence
for (int i = 0; i < nums.size(); i++) {
// Can we add the current num to the current sequence?
if (i == startCurrent || nums.get(i).equals(nums.get(i - 1)))) {
// We can extend the current sequence with this i:
int lengthCurrent = i - startCurrent + 1;
if (lengthCurrent > lengthBest) { // Current length better?
// New optimum:
startBest = startCurrent;
lengthBest = lengthCurrent;
}
} else {
// A different num, start here.
// As we had already a real sequence (i != 0), no need for
// checking for a new optimum with length 1.
startCurrent = i;
}
}
// Now we found the best solution.
// Create the result:
StringBuilder result = new StringBuilder();
for (int i = 0; i < nums.size(); i++) {
result.append(nums.get(i));
}
// Insert the right ')' first as its index changes by 1 after inserting '('.
result.insert(startBest + lengthBest, ")");
result.insert(startBest, "(");
return result.toString();
}
The first problem is how to find the end of a sequence, and set the correct start of the sequence.
The problem with the original algorithm is that there is handled just one sequence (one subsequence start).
The way you have suggested could work. And then, if newcount is greater than oldcount, you'll want to store an additional number in another variable - the index of the where the longest sequence begins.
Then later, you can go and insert the ( at the position of that index.
i.e. if you have 11223456666.
The biggest sequence starts with the first number 6. That is at index 7, so store that 7 in a variable.
I think you need to iterate the entire list even though the current count is lower than the oldCount, what about e.g. 111224444?
Keep 4 variables while iterating the list: highestStartIndex, highestEndIndex, highestCount and currentCount. Iterate the entire list and use currentCount to count equal neighbouring numbers. Update the highest* variables when a completed currentCount is higher than highestCount. Lastly write the numbers out with paranthesis using the *Index variables.
In my program, i "deleted" an element by turning it into a null as you can't delete an element from an array so employee [i] = null. However, I was wondering, if I wanted to work with the array that had a null element, like add all the numbers in the array, how do I do this without any problems?
[UPDATE:]
My array contains the first names, last names and ages of 4 employees, I've "deleted" one of the employees details by making it null. As per all of the suggestions I got, I tried to add all the ages using:
int sum = 0;
for (int i = 0; i < employee.length; i++) {
if (employee[i] != null)
sum += employee[i].getAge();
}
but all I get is that sum = 1.
If the only operation you're going to perform on your array is the sum of all elements, it would make more sense to set the deleted elements to 0 instead of null. This way, you will not need the extra null check on every iteration.
You have to check if that element is null or not. If it is, add to the sum. If not, do nothing.
int sum = 0;
for (int i = 0; i < employee.length; i++) {
if (employee[i] != null)
sum += employee[i];
}
public int addAllNums(int[] nums)
{
int sum=0;
for(int i=0;i<nums.length;i++)
{
if(nums[i]!=null)sum+=nums[i];
}
}
You just have to iterate over your array and check if the current employee is not null :
int sum = 0;
for(int i = 0; i < employee.length; i++) {
if(employee[i] != null) {
sum += employe[i].getNumber();
}
}
This question already has answers here:
How to efficiently remove duplicates from an array without using Set
(48 answers)
Closed 8 years ago.
I have written a method to count the number of occurrences of the words in a word file. Prior, in another method, i have sorted the words to appear in alphabetical order. There for a sample input into this method will look like this:
are
away
birds
birds
going
going
has
My question is.. How do i delete the repeated occurrences in this method? (after counting ofcoz) I have tried to use another string array to copy the unique ones into that string array, but i get a null pointer exception.
public static String[] counter(String[] wordList)
{
for (int i = 0; i < wordList.length; i++)
{
int count = 1;
for(int j = 0; j < wordList.length; j++)
{
if(i != j) //to avoid comparing itself
{
if (wordList[i].compareTo(wordList[j]) == 0)
{
count++;
}
}
}
System.out.println (wordList[i] + " " + count);
}
return wordList;
}
Any help will be much appreciated.
Oh, and my current output looks something like this:
are 1
away 1
birds 2
birds 2
going 2
going 2
has 1
I would prefer using Map to store word occurrence. Keys in the map are stored in Set so it can't be duplicated. What about something like this?
public static String[] counter(String[] wordList) {
Map<String, Integer> map = new HashMap<>();
for (int i = 0; i < wordList.length; i++) {
String word = wordList[i];
if (map.keySet().contains(word)) {
map.put(word, map.get(word) + 1);
} else {
map.put(word, 1);
}
}
for (String word : map.keySet()) {
System.out.println(word + " " + map.get(word));
}
return wordList;
}
I already posted an answer on this question. Your question is almost identical - he was having problems creating another array and getting an NPE too.
This is what I came up with (assuming the array is sorted):
public static String[] noDups(String[] myArray) {
int dups = 0; // represents number of duplicate numbers
for (int i = 1; i < myArray.length; i++)
{
// if number in array after current number in array is the same
if (myArray[i].equals(myArray[i - 1]))
dups++; // add one to number of duplicates
}
// create return array (with no duplicates)
// and subtract the number of duplicates from the original size (no NPEs)
String[] returnArray = new String[myArray.length - dups];
returnArray[0] = myArray[0]; // set the first positions equal to each other
// because it's not iterated over in the loop
int count = 1; // element count for the return array
for (int i = 1; i < myArray.length; i++)
{
// if current number in original array is not the same as the one before
if (!myArray[i].equals(myArray[i-1]))
{
returnArray[count] = myArray[i]; // add the number to the return array
count++; // continue to next element in the return array
}
}
return returnArray; // return the ordered, unique array
}
Sample input/output:
String[] array = {"are", "away", "birds", "birds", "going", "going", "has"};
array = noDups(array);
// print the array out
for (String s : array) {
System.out.println(s);
}
Outputs:
are
away
birds
going
has
I want to be able to tell if a any number in an int[] appears 3 or more times? How can I do this?
Would be awesome to have method
boolean hasTriples(int[] numbers) {
//some code
}
Create a Map<Integer, Integer>, and let integer n map to the number of occurrences of n.
Loop through the array to populate the map, then loop through the keys in the map to check which keys map to a value >= 3.
Here's some code to get you started:
int[] arr = { 1, 3, 2, 3, 3, 4, 2, 2 };
Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
// Count occurrencies
for (int i : arr) {
if (!counts.containsKey(i))
counts.put(i, 0);
counts.put(i, 1 + counts.get(i));
}
// Print how many times each number occurs in arr.
for (int i : counts.keySet())
System.out.printf("i: %d, count: %d%n", i, counts.get(i));
public boolean anyRepeatThreeTimes( int [] array ) {
Map<Integer, Integer > map = new HashMap<Integer, Integer>();
for ( int index = 0; index < array.length; index++ ) {
Integer total = map.get(array[ index ]);
int count;
if ( total == null ) {
count = 1;
}
else {
count = total + 1;
if ( count >= 3 ) {
return true;
}
}
map.put( array[ index ], count );
}
return false;
}
Here's what's going on:
You pass in the array of ints.
You set up a map of array values to a count of the value.
You walk the array. For each integer in the array:
a. you retrieve the current count for that array value
b. if no value exists, then start with a value of 1
c. if a value does exist in the map for the given value, add one to it
d. if the value retrieved from the map + 1 exceeds your limit of 3, then you have demonstrated that there is a value in the array that is repeated at least three times.
if you make it to the end of the loop without ever returning true, then return false instead, because no value is repeated 3 times.
Here is a way to do it without using any extra classes such as the Map class. It might be slower but hopefully is easier to understand.
public boolean hasTriples(int[] list) {
for (int i = 0; i < list.length; i++){
int duplicates = 0;
for (int j = i+1; j < list.length; j++){
if (list[i] == list[j]) {
duplicates++;
if (duplicates >= 3) return true;
}
}
}
return false;
}
Here is what this code is doing. The outer for loop is running through the list to make sure that every value is checked for duplicates. The inner loops runs through the remeinder of the list to check how many duplicate values there are. If three or more duplicates are found the function will return true and not process the rest of the list. If the outer for loop finishes without the method returning true false is returned as there must not be any three duplicates.
Hope this helps!