I want to find the majority in array (number that appears most of the time).
I have a sorted array and use these cycles:
for(int k = 1;k < length;k++)
{
if(arr[k-1] == arr[k])
{
count++;
if(count > max)
{
max = count;
maxnum = arr[k-1];
}
} else {
count = 0;
}
}
or
for(int h=0;h<length;h++)
{
for(int l=1;l<length;l++)
{
if(arr[h] == arr[l])
{
count++;
if(count > max)
{
max = count;
maxnum = arr[h];
}
} else count = 0;
}
}
they are similiar. When i try them on small arrays everything seems to be ok. But on a long run array with N elements 0<=N<=500000, each element K 0<=K<=10^9 they give wrong answers.
Here is solution with mistake http://ideone.com/y2gvnX. I know there are better algos to find majority but i just need to know where is my mistake.
I really can't find it :( Will really appreciate help!
First of all, you should use the first algorithm, as your array is sorted. 2nd algorithm runs through the array twice unnecessarily.
Now your first algorithm is almost correct, but it has two problems: -
The first problem is you are setting count = 0, in else part,
rather it should be set to 1. Because every element comes at least
once.
Secondly, you don't need to set max every time in your if. Just
increment count, till the if-condition is satisfied, and as soon
as condition fails, check for the current count with current
max, and reset the current max accordingly.
This way, your max will not be checked on every iteration, but only when a mismatch is found.
So, you can try out this code: -
// initialize `count = 1`, and `maxnum = Integer.MIN_VALUE`.
int count = 1;
int max = 0;
int maxnum = Integer.MIN_VALUE;
for(int k = 1;k < length;k++)
{
if(arr[k-1] == arr[k]) {
count++; // Keep on increasing count till elements are equal
} else {
// if Condition fails, check for the current count v/s current max
if (max < count) { // Move this from `if` to `else`
max = count;
maxnum = arr[k - 1];
}
count = 1; // Reset count to 1. As every value comes at least once.
}
}
Note : -
The problem with this approach is, if two numbers say - 1 and 3, comes equal number of times - which is max, then the max count will be counted for 3 (assuming that 3 comes after 1, and maxnum will contain 3 and ignore 1. But they both should be considered.
So, basically, you cannot use a for loop and maintain a count to take care of this problem.
A better way is to create a Map<Integer, Integer>, and store the count of each value in there. And then later on sort that Map on value.
Your first algorithm looks correct to me. The second one (which is what your linked code uses) needs some initialization each time through the loop. Also, the inner loop does not need to start at 1 each time; it can start at h + 1:
for(int h=0; h<length; h++)
{
count = 1; // for the element at arr[h]
for(int l=h + 1; l<length; l++)
{
if(arr[h] == arr[l])
{
count++;
}
}
if(count > max)
{
max = count;
maxnum = arr[h];
}
}
The first algorithm is much better for sorted arrays. Even for unsorted arrays, it would be cheaper to sort the array (or a copy of it) and then use the first algorithm rather than use the second.
Note that if there are ties (such as for the array [1, 1, 2, 2, 3] as per #Rohit's comment), this will find the first value (in the sort order) that has the maximum count.
The error I can readily see is that if all elements are distinct, then the max at end is 0.
However it has to be 1.
So when you update count in "else" case, update it to 1 instead of 0, as a new element has been discovered, and its count is 1.
Your first algorithm only makes sense if the array is sorted.
Your second algorithm just sets count to zero in the wrong place. You want to set count to zero before you enter the inner for loop.
for(int h=0;h<length;h++)
{
count = 0;
for(int l=0;l<length;l++)
{
if(arr[h] == arr[l])
{
count++;
if(count > max)
{
max = count;
maxnum = arr[h];
}
}
}
}
Also, you don't need to check count each time in the inner loop.
max = 0;
for(int h=0;h<length;h++)
{
count = 0;
for(int l=0;l<length;l++)
{
if(arr[h] == arr[l])
count++;
}
if(count > max)
{
max = count;
maxnum = arr[h];
}
}
Related
Here is my solution:
public static int minimumAbsoluteDifference(List<Integer> arr) {
int absValues = 0;
int maxNum = Integer.MAX_VALUE;
Collections.sort(arr);
for (int i = 0; i < arr.size() - 1; i++){
absValues = Math.abs(arr.get(i) - arr.get(i + 1));
}
int absValuesDiff = Math.min(absValues, maxNum);
return absValuesDiff;
}
I pass small test cases, but not ones with a larger data set.
As L_Cleo suggested, you indeed check the minimum value only once.
Instead, you should check it on every iteration of the loop:
public static int minimumAbsoluteDifference(List<Integer> arr) {
int absValue = Integer.MAX_VALUE;
Collections.sort(arr);
for (int i = 0; i < arr.size() - 1; i++) {
absValue = Math.min(absValue, Math.abs(arr.get(i) - arr.get(i + 1)));
}
return absValue;
}
I added the minimum check on every iteration. The checking is done between the absValue and the absolute difference of the current loop iteration.
By the end of the loop, absValue will contain the minimum value, because you have compared it to every other possibility.
The longer explanation why this works is this:
The reason why updating the absValue in each loop iteration is enough is this: absValue's first value is Integer.MAX_VALUE. This means that any other value will be smaller than absValue. In the first loop iteration, absValue is updated with the first absolute difference. In all other iterations, the code will always update absValue with the smaller value between the current absValue and the absolute difference you calculate on each iteration.
This guarantees that, for all iterations, the smallest value will be stored in absValue at some point, and in the further iterations, absValue value will not change.
The problem in your solution is that you're not checking all possible couples within the array of numbers.
With this for loop, for example:
for (int i = 0; i < arr.size() - 1; i++) {
absValues = Math.abs(arr.get(i) - arr.get(i + 1));
}
And iterating over the simple array 1, 4, 6, 7, you would be checking the couples [1,4], [4,6] and [6,7], but you're still missing 1,7 and 4,7.
So step number one would be to iterate over the array per every number of the array (knowing that the order of the pairs doesn't matter [1,6] == [6,1] in this case, you will have to check 1 less number every iteration of the outer loop... here is an example of a correct for loop:
public static int minimumAbsoluteDifference(List<Integer> arr) {
Collections.sort(arr);
int minAbsoluteValue = Integer.MAX_VALUE;
for(int i=0; i < arr.size() - 1; i++) {
for(int j=i+1; j < arr.size(); j++)
minAbsoluteValue = Math.min(Math.abs(arr.get(i) - arr.get(j)), minAbsoluteValue);
}
return minAbsoluteValue;
}
As you can see, another missing part in your solution is the tracking of the minimum value. You're checking the minimum value between the last iterated couple and the maxInteger value only once, while you have to that for every couple.
This might not be the most efficient solution...
I solved a variation of the knapsack problem by backtracking all of the possible solutions. Basically 0 means that item is not in the backpack, 1 means that the item is in the backpack. Cost is the value of all items in the backpack, we are trying to achieve the lowest value possible while having items of every "class". Each time that a combination of all classes is found, I calculate the value of all items and if it's lower than globalBestValue, I save the value. I do this is verify().
Now I'm trying to optimize my recursive backtrack. My idea was to iterate over my array as it's being generated and return the generator if the "cost" of my generated numbers is already higher then my current best-value, therefore the combination currently being generated can't be the new best-value and can be skipped.
However with my optimization, my backtrack is not generating all the values and it actually skips the "best" value I'm trying to find. Could you tell me where the problem is?
private int globalBestValue = Integer.MAX_VALUE;
private int[] arr;
public KnapSack(int numberOfItems) {
arr = new int[numberOfItems];
}
private void generate(int fromIndex) {
int currentCost = 0; // my optimisation starts here
for (int i = 0; i < arr.length; i++) {
if (currentCost > globalBestValue) {
return;
}
if (arr[i] == 1) {
currentCost += allCosts.get(i);
}
} // ends here
if (fromIndex == arr.length) {
verify();
return;
}
for (int i = 0; i <= 1; i++) {
arr[fromIndex] = i;
generate(fromIndex + 1);
}
}
public void verify() {
// skipped the code verifying the arr if it's correct, it's long and not relevant
if (isCorrect == true && currentValue < globalBestValue) {
globalBestValue = currentValue;
}else{
return;
}
}
Pardon my bluntness, but your efforts at optimizing an inefficient algorithm can only be described as polishing the turd. You will not solve a knapsack problem of any decent size by brute force, and early return isn't enough. I have mentioned one approach to writing an efficient program on CodeReview SE; it requires a considerable effort, but you gotta do what you gotta do.
Having said that, I'd recommend you write the arr to console in order to troubleshoot the sequence. It looks like when you go back to the index i-1, the element at i remains set to 1, and you estimate the upper bound instead of the lower one. The following change might work: replace your code
for (int i = 0; i <= 1; i++) {
arr[fromIndex] = i;
generate(fromIndex + 1);
}
with
arr[fromIndex] = 1;
generate(fromIndex + 1);
arr[fromIndex] = 0;
generate(fromIndex + 1);
This turns it into a sort of greedy algorithm: instead of starting with 0000000, you effectively start with 1111111. And obviously, when you store the globalBestValue, you should store the actual data which gives it. But the main advice is: when your algorithm behaves weirdly, tracing is your friend.
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.
I am trying to practice algorithms before i start my undergrad in computer science and i am struggling really bad to write algorithms. I understand them once i've been taught them and break them down but when I am trying to do my own, it fails miserable. I am trying a exercise question in a programming textbook, where i have an array and i have to output the largest value or if the array is empty, i have to display -1.
This was the best i can come up with but it still falls way short. Any pointers on what exactly I'm doing wrong.
for(i = 0;i < array.length-1;i++)
if(array[i] == 0){
empty = true;
n = -1;
System.out.println(n);
}else{
largest = array[0];
if(array[i] > largest){
largest = array[i];
System.out.println(array[i]);
}
}
I see that -1 displayed 10 times but i have found no solution for this and if the array is full, it provides me one then one value.
If you're struggling with algorithms, it helps sometimes not to look at them as algorithms but real-world problems.
Say you are in a shop buying cheese and your task is to pick a pack of cheese which has the latest expiration date. Now imagine the situation: standing at the cheese section looking for the best yummy cheese...
First, you look if there is any. If not, return empty handed.
If there are some packs, go through them looking for the best. You've got probably only one hand free, holding the basket in the other one, so...
Initially, pick the first cheese
Then go through the packs one by one. If you find cheese better than you have in your hand, put the one you're holding down and take the better one.
Now, let's put this to a programing language:
int[] cheeseExpirations = new int[] { ... };
if (cheeseExpirations.length == 0) {
System.out.println(-1); // no cheese :(
} else {
int myCheese = cheeseExpirations[0]; // take the first pack; better a sparrow in the hand than a pigeon on the roof...
for (int i = 0; i < cheeseExpirations.length; i++) { // idiomatic array iteration
int currentCheese = cheeseExpirations[i];
if (currentCheese > myCheese ) { // found a better one
myCheese = currentCheese; // just take it
}
}
System.out.println(bestCheese);
}
Is it clearer now? Like Richard Feynman said, using your imagination and examples is important:
I had a scheme, which I still use today when somebody is explaining something that I'm trying to understand: I keep making up examples.
For instance, the mathematicians would come in with a terrific theorem, and they're all excited. As they're telling me the conditions of the theorem, I construct something which fits all the conditions. You know, you have a set (one ball)-- disjoint (two balls). Then the balls turn colors, grow hairs, or whatever, in my head as they put more conditions on.
Finally they state the theorem, which is some dumb thing about the ball which isn't true for my hairy green ball thing, so I say "False!" [and] point out my counterexample.
You are checking the length of the array in each loop. This means it won't be checked unless the array has some object, which is just what we don't want.
But, in fact, you are not checking the array length:
if(array[i] == 0) tests if the item of array at index i is 0. To test the length of the array, you have to do if (array.length > 0). Remember you have to do this before the for loop, so it would be something like this:
if(array[i] == 0){
empty = true;
n = -1;
System.out.println(n);
}
for(i = 0;i < array.length-1;i++)
largest = array[0];
if(array[i] > largest){
largest = array[i];
System.out.println(array[i]);
}
}
But, in each loop you are reassigning largest to the first array element, which breaks the algorithm. So you must move that line before the for loop.
if(array[i] == 0){
empty = true;
n = -1;
System.out.println(n);
}
largest = array[0];
for(i = 0;i < array.length-1;i++)
if(array[i] > largest){
largest = array[i];
System.out.println(array[i]);
}
}
A few things:
if(array[i] == 0)
does not check if the array is empty, it checks if the value stored at index i of the array is equal to zero. You probably want something like:
if(array != null && array.length == 0) {
return -1;
}
before the for loop executes.
The rest of your code looks close. The print statement inside of the else clause is unnecessary. You just need to return the value of largest after the for loop executes.
This code is rather strange in general. Why do you consider an array empty as soon as you reach an element that is 0? And why do you continue search, if the array is empty? Last but not least: why do you ignore the last element in the array?
There are plenty of solutions for this that are a lot simpler:
Without any java-api:
if(array.length == 0)
return -1;
int max = Integer.MIN_VALUE;
for(int i = 0 ; i < array.length ; i++)
if(max < array[i])
max = array[i];
return max;
A lazy solution using Arrays.sort() (not exactly elegant, but short)
Arrays.sort(array);
return array[array.length - 1];
Using java8:
return Arrays.stream(array).min((a , b) -> new Integer(a).compareTo(b)).orElse(-1);
Lets take a look at your code
for(i = 0;i < array.length-1;i++)//You will never reach the last number
if(array[i] == 0){//Here you check if the first item equals zero. Gives error if there is no first item.
empty = true;//why do you need this, you never use it.
n = -1;
System.out.println(n);
}else{
largest = array[0];//Why setting largest, do dont know if it is actually bigger
if(array[i] > largest){
largest = array[i];
System.out.println(array[i]);
}
}
Improved version:
largest = -1;//set it by default
for(i = 0;i < array.length;i++)//if length is 10 iMax = 9, which is the tenth item.
if(array[i]>largest){//if larger set the new value
largest = array[i];
}
}
System.out.println(largest);//print the largest number.
if(array.length == 0){
empty = true;
n = -1;
System.out.println(n);
}else{
largest = array[0];
for(i = 1; i < array.length; i++)
if(array[i] > largest){
largest = array[i];
}
System.out.println(largest);
}
First what i did is check if the array is empty. If it is then skip the else and output the -1. If the array is not empty set the largest to the first element and then loop through all other elements. Noticed I changed i = 1 because element 0 is already the largest. Also I removed the -1 to the array length because i will stop 1 before the length (which will be the last index of final element). Finally I moved the print of the largest value outside of the if statement and for loop so that it only gets printed once at the very end.
First check if the array is empty
if(array != null && array.length == 0) {
If it is print -1
System.out.println(-1 + "");
}
Now you are ready to go through the array. But before you do create a variable that will keep track of the largest value. I set it to the first element in the array (since we know that it has at least one element since we already determined that it isn't empty)
else {
int largest = array[0];
Then, loop through the array
for(i = 0;i < array.length-1;i++) {
Get every element one at a time using i to access the ith element
int current = array[i];
Then compare it to the largest. If it's greater than the largest so far, save it as the largest.
if (current>largest) {
current = largest;
}
Keep doing that until finished looping through the array
}
Then print out the largest
System.out.println(largest + "");
}
I am trying to loop through an arraylist and gradually remove an element every 3 indices. Once it gets to the end of the arraylist I want to reset the index back to the beginning, and then loop through the arraylist again, again removing an element every 3 indices until there is only one element left in the arraylist.
The listOfWords is an array with a length of 3 that was previously filled.
int listIndex = 0;
do
{
// just to display contents of arraylist
System.out.println(listOfPlayers);
for(int wordIndex = 0; wordIndex < listOfWords.length; wordIndex++
{
System.out.print("Player");
System.out.print(listOfPlayers.get(wordIndex));
System.out.println("");
listIndex = wordIndex;
}
listOfPlayers.remove(listOfPlayers.get(listIndex));
}
while(listOfPlayers.size() > 1);
I have tried to implement for several hours yet I am still having trouble. Here's what happens to the elements of the arraylist:
1, 2, 3, 4
1, 2, 4
1, 2
Then it throws an 'index out of bounds error' exception when it checks for the third element (which no longer exists). Once it reaches the last element I want it to wrap around to the first element and continue through the array. I also want it to start where it left off and not from the beginning once it removes an element from the arraylist.
Maybe I have just missed the boat, but is this what you were after?
import java.util.ArrayList;
import java.util.Random;
public class Test {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
Random r = new Random();
//Populate array with ten random elements
for(int i = 0 ; i < 4; i++){
numbers.add(r.nextInt());
}
while(numbers.size() > 1){
for(int i = 0; i < numbers.size();i++){
if(i%3 == 0){//Every 3rd element should be true
numbers.remove(i);
}
}
}
}
}
You could move every third element to a temporary list then use List#removeAll(Collection) to remove the items when you finish each loop...until the master list was empty...
Lets back up and look at the problem algorithmically.
Start at the first item and start counting.
Go to the next item and increment your count. If there is no next item, go to the beginning.
If the count is '3', delete that item and reset count. (Or modulo.)
If there is one item left in the list, stop.
Lets write pseudocode:
function (takes a list)
remember what index in that list we're at
remember whether this is the item we want to delete.
loop until the list is size 1
increment the item we're looking at.
increment the delete count we're on
should we delete?
if so, delete!
reset delete count
are we at the end of the list?
if so, reset our index
Looking at it this way, it's fairly easy to translate this immediately into code:
public void doIt(List<String> arrayList) {
int index = 0;
int count = 0;
while(arrayList.size() != 1) {
index = index + 1;
count = count + 1; //increment count
String word = arrayList.get(index);//get next item, and do stuff with it
if (count == 3) {
//note that the [Java API][1] allows you to remove by index
arrayList.remove(index - 1);//otherwise you'll get an off-by-one error
count = 0; //reset count
}
if (index = arrayList.size()) {
index = 0; //reset index
}
}
}
So, you can see the trick is to think step by step what you're doing, and then slowly translate that into code. I think you may have been caught up on fixing your initial attempt: never be afraid to throw code out.
Try the following code. It keeps on removing every nth element in List until one element is left.
List<Integer> array = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
int nth = 3;
int step = nth - 1;
int benchmark = 0;
while (array.size() > 1) {
benchmark += step;
benchmark = benchmark > array.size() - 1 ? benchmark % array.size() : benchmark;
System.out.println(benchmark);
array.remove(array.get(benchmark));
System.out.println(array);
}
You could use a counter int k that you keep incrementing by three, like k += 3. However, before you use that counter as an index to kick out any array element, check if you already went beyond and if so, subtract the length of this array from your counter k. Also make sure, to break out of your loop once you find out the array has only one element left.
int k = -1;
int sz = list.length;
while (sz > 1)
{
k += 3;
if (k >= sz)
{
k -= sz;
}
list.remove(k);
sz --;
}
This examples shows that you already know right away how often you will evict an element, i.e. sz - 1 times.
By the way, sz % 3 has only three possible results, 0, 1, 2. With a piece of paper and a cup of coffee you can find out what the surviving element will be depending on that, without running any loop at all!
You could try using an iterator. It's late irl so don't expect too much.
public removeThirdIndex( listOfWords ) {
Iterator iterator = listOfWords.iterator
while( iterator.hasNext() ){
iterator.next();
iterator.next();
iterator.next();
iterator.remove();
}
}
#Test
public void tester(){
// JUnit test > main
List listOfWords = ... // Add a collection data structure with "words"
while( listOfWords.size() < 3 ) {
removeThirdIndex( listOfWords ); // collections are mutable ;(
}
assertTrue( listOfWords.size() < 3 );
}
I would simply set the removed to null and then skip nulls in the inner loop.
boolean continue;
do {
continue = false;
for( int i = 2; i < list.length; i += 3 ){
while( list.item(i++) == null && i < list.length );
Sout("Player " + list.item(--i) );
continue = true;
}
} while (continue);
I'd choose this over unjustified shuffling of the array.
(The i++ and --i might seem ugly and may be rewritten nicely.)