Remove every 3rd element in arraylist - java

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.)

Related

Java ArrayList break remove

I was trying to write a code that would remove all zeros before the first non-zero element in an integer ArrayList, scanned from index 0. However, the code keeps on removing a fixed no. of zeros after the first non-zero element. can anybody figure out why?(Sorry if format of question posted is not ideal. this is my first time.)
For the following code, the intended output was [2 0 0 0 0 0], but the output received was [2 0 0]
class Zeroeliminator {
public static void main(String args[]) {
ArrayList < Integer > arr = new ArrayList < Integer > ();
arr.add(0); // A
arr.add(2);
for (int i = 2; i < 7; i++)
arr.add(0);
System.out.println(arr.size());
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i) != 0) {
break;
}
System.out.println(arr.get(i));
arr.remove(i);
}
System.out.println(arr.size());
ListIterator < Integer > itr = arr.listIterator(0);
while (itr.hasNext()) {
System.out.print(itr.next() + " ");
}
System.out.println();
}
}
The problem with your code is that when you remove an element, all of the elements after it are shifted down by one. So, the state of one iteration looks like this:
arr=[0 2 0 0], i = 0
// Remove element i
arr=[2 0 0], i = 0
// Increment i
arr=[2 0 0], i = 1
On the next iteration, you'll check for i = 1, and ignore the fact there was a 2 there, because you never read its value.
You can fix this by decrementing i each time you remove an element. But you don't then need i at all, because you're removing the list prefix. Instead, you could just use:
while (!arr.isEmpty() && list.get(0) == 0) {
arr.remove(0);
}
A better (more efficient) approach to this is to scan through the list first to find the first non-zero element, and then delete the preceding elements in one go:
int i = 0;
while (i < arr.size() && arr.get(i) == 0) {
i++;
}
arr.subList(0, i).clear();
Removing 1 element from the front of an ArrayList is O(size), because all of the other elements have to be shifted down by one; so removing multiple elements is O(#removed * size).
The approach using sublist does all of the shifts in one go, so it is O(size).
You have to decrement i when you remove an element, since the indices of the ArrayList elements following the removed element are decremented.
for(int i = 0; i < arr.size(); i++)
{
if(arr.get(i) != 0){
break;
}
System.out.println(arr.get(i));
arr.remove(i);
i--;
}

Find value that occurs consecutively most nunber of times in array

The following code is in java lang:
int[] array = {1,2,2,3,3,3,2,2,1};
int k = 2;
What i need to do is find the value (in this case 3), that occurs consecutively more than k times. There can be only one value that occurs>k and if no such value exists, print -1
Explanation: 1 occurs only 1 time consecutively. 2 occurs 2 times but its not>k. 3 occurs 3 times, which is>k. Since, there can be only one possible answer, you can stop searching for answer in further values and print 3.
The time limit for code is 0.25s
Update : What I've tried so far
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
int[] array = {1,2,2,3,3,3,2,2,1};
int k=2;
int result = -1;
for(int lom =0;lom<array.length-1;lom++){
int temp = 0;
int lo=lom;
while(array[lo]==array[lom]){
temp+=1;
if(lo<array.length){lo++;}else{break;}
}
if(temp>k){
result = array[lom];
break;
}
}
System.out.println(result);
}
}
When I try to solve about 10 queries through this, it takes up 2 seconds. I got to complete it in 1. Can you suggest some method to optimize the code, so that I can research upon it and then try again.
You need not to traverse twice with while loop and lo
1.) Traverse using loop
2.) If keep a track of element sequence
3.) if element changes , reset track
4.) when the track reaches above k break the loop
int[] array = {1,2,2,3,3,3,2,2,1};
int k = 2;
// get first element
int element=array[0];
// set tot to 1
int tot=1;
for (int i = 1; i < array.length; i++) {
// if values are same , increment tot
if (element==array[i]) {
tot++;
}else {
// set element to new found value and tot = 1
element=array[i];
tot=1;
}
// when any elements exceeds the k limit
// print element and stop the loop
if (tot>k) {
System.out.println(array[i]);
break;
}
}
// to print -1 if tot > k never reached
if (!(tot>k)) {
System.out.println(-1);
}

Find largest sequence within an arraylist

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.

Removing contiguous duplicates in ArrayList [Java]

I am doing a simple Java program and I need to remove all of the contiguous duplicates in a String ArrayList.
My String ArrayList is something like this:
list = [a,b,c,c,d,a,b,c,d]
My goal is removing all (and only!) the contiguous duplicates so that the result would be: [a,b,c,d,a,b,c,d]. As you can see, one of the two contiguous "c" has been removed.
I tried something like this:
for (int i = 0; i<list.size(); i++) {
if (list.get(i).compareTo(list.get(i+1))==0) {
positionToRemove.add(i);
}
}
Where positionToRemove will at the end contain all the position of the contiguous elements which I will then remove using list.remove() (still not done)
Unfortunately I get
java.lang.IndexOutOfBoundsException
I am quite positive there is a very simple way to achieve this but I can't remember it at the moment!
There is no need to store the indexes of the elements you need to remove. Just remove it directly by:
int size = list.size();
for (int i = size - 1; i >= 1; i--) {
if (list.get(i).compareTo(list.get(i - 1)) == 0) {
list.remove(i);
}
}
In the last iteration of the for loop, list.get(i+1) goes beyond the bounds of the list and thus the IndexOutOfBoundsException. In any array/arraylist, the maximum accessible index is always size/length - 1.
To fix that you need to change your logic a bit.
for (int i = 1; i<list.size(); i++) {
if (list.get(i-1).compareTo(list.get(i))==0) {
positionToRemove.add(i);
}
}
When you access the List using index + 1 or i+1, you overstep the bounds of the List on the last iteration. You can fix this by setting the conditional for your for loop to i < list.size() -1.
for (int i = 0; i < list.size() -1; i++) {
if (list.get(i).compareTo(list.get(i+1))==0) {
positionToRemove.add(i);
}
}
It should not reach the length of your list. You must shutdown the traverses at size -1.
for (int i = 0; i<list.size() - 1; i++) {
if (list.get(i).compareTo(list.get(i+1))==0) {
positionToRemove.add(i);
}
}
Where positionToRemove will at the end contain all the position of the
contiguous elements which I will then remove using list.remove()
(still not done)
Instead of storing each position, you could start from the end of the list and directly remove the current element if it's the same as its left neighbour. Using this, you don't need to create another list containing the indexes of the objects you want to remove.
List<String> list = new ArrayList<>(Arrays.asList("a","b","c","c","d","a","b","c","d"));
for(int i = list.size() - 1; i > 0; i--){
if(list.get(i).compareTo(list.get(i-1)) == 0){
list.remove(i);
}
}
System.out.println(list);
Which outputs:
[a, b, c, d, a, b, c, d]
You can do this with Java 7, using iterator.
Iterator<Integer> iterator = collection.values().iterator();
Integer previousValue = null;
while(iterator.hasNext()) {
Integer currentValue = iterator.next();
if(currentValue.equals(previousValue)){
iterator.remove();
}
previousValue = currentValue;
}

Where is the mistake? Finding majority

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];
}
}

Categories