Java ArrayList break remove - java

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

Related

Rearrange elements in an integer array in a fashion where-you first replace and then move the replaced integer to first part of the array

I came across a Hackerearth coding problem where you have to perform the following tasks over an integer array-
Search for a particular number in the array and replace it's occurrences with 1
Move all the 1s to the first part of the array, maintaining the original order of the array
For example- if we have an integer array {22,1,34,22,16,22,35,1}, here we search for the number "22" (let us assume it is present in the array), replace it with 1 and move all those 1s (including the 1s already present) to the first part of the array and the resultant array should look like {1,1,1,1,1,1,34,16,35} -maintaining the original order of the array, preferably in Java.
I actually have coded a solution and it works fine but is not optimal, can anyone help me find an optimal solution (w.r.t. time-space complexity)?
Below is my solution-
public static void main(String[] args) {
int[] n = rearr(new int[] {22,1,34,22,16,22,1,34,1}, 22);
for(int i=0; i<n.length; i++) {
System.out.print(n[i]+" ");
}
}
static int[] rearr(int[] a, int x) {
int[] temp = new int[a.length];
int j=0, c=0, k=0;
//search and replace
for(int i=0; i<a.length; i++) {
if(a[i] == x) {
a[i] = 1;
}
}
//shift all 1s to first part of array or shift all non-1s to last part of the array
for(int i=0; i<a.length; i++) {
if(a[i] != 1) {
temp[j] = a[i];
j++;
}
if(a[i] == 1) {
c++;
}
}
j=0;
for(int i=0; i<a.length && c>0; i++, c--) {
a[i] = 1;
j++;
}
for(int i=j ;i<a.length; i++) {
a[i] = temp[k];
k++;
}
return a;
}
This can be done in linear time and space complexity, by returning a completely new list instead of modifying the original list.
static int[] rearr(int[] a, int x) {
// allocate the array we'll return
int[] b = new int[a.length];
int fillvalue = 1;
// iterate backwards through the list, and transplant every value OTHER than
// (x or 1) to the last open index in b, which we track with b_idx
int b_idx = b.length - 1;
for (int i = a.length - 1; i >= 0; i--) {
if (a[i] != x && a[i] != fillvalue)) {
b[b_idx] = a[i];
b_idx--;
}
}
// once we've gone through and done that, fill what remains of b with ones
// which are either original or are replacements, we don't care
for (int i = b_idx; i >= 0; i--) {
b[i] = fillvalue;
}
return b;
}
This is linear space complexity because it requires additional space equal to the size of the given list. It's linear time complexity because, in the worst case, it iterates over the size of the list exactly twice.
As a bonus, if we decide we want to leave the original 1s where they were, we can do that without any trouble at all, by simply modifying the if condition. Same if we decide we want to change the fill value to something else.
Doing this with constant space complexity would require O(n^2) list complexity, as it would require swapping elements in a to their proper positions. The easiest way to do that would probably be to do replacements on a first run through the list, and then do something like bubblesort to move all the 1s to the front.
This can be done in a single iteration through the array. We can use 2 pointer approach here where we will use on pointer to iterate through the array and other one to point to the index of 1 in the array.
The code is below:
public static void main(String[] args) {
// input array
int[] arr = { 22, 1, 34, 22, 16, 22, 35, 1, 20, 33, 136 };
// element to be replaced
int x = 22;
int j = -1;
for (int i = arr.length - 1; i >= 0; i--) {
if (arr[i] == 1 || arr[i] == x) {
if (j == -1) {
j = i;
}
// incase arr[i]==x
arr[i] = 1;
} else {
if (j != -1) {
arr[j] = arr[i];
arr[i] = 1;
j--;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
Here we initialise j=-1 since we consider there are no 1's present in the array.
Then we start iterating the array from the end towards the starting of the array as we have to push all the 1's to the starting of the array. Now when we reach to 1 or x (particular number in your case), we check if this is first occurrence of the x or 1, if yes then we initialise the j with this index and change arr[i] = 1 because this could be equal to x then we need to make it 1. If the arr[i] is not 1 or x it means its a number which we need to push at back of the array. We check if we have position of 1 or j=-1. If j=-1 it means this number is already pushed back at end of array else we swap the number at i and j, and decrement j by 1.
At the end of the array we will have the array sorted in a fashion which is required.
Time Complexity: Since we are only iterating the array one, hence the time complexity is O(n).
Space Complexity: Since there are no extra space being used or constant space being used hence the space complexity is O(1)

Find the first duplicate with the minimal next occurrence

I am trying to solve a challenge,
I wrote my solution and it passes all test cases except some hidden test cases. I can't think another case in which my method fails and don't know what to do anymore.
Here it is:
int firstDuplicate(int[] a) {
int[] indexCount;
int duplicate, temp;
boolean check;
duplicate = -1; temp = a.length;
indexCount = new int[a.length];
check = false;
for( int i = 0; i < a.length; i++ ){
if( indexCount[a[i]-1] == 0 ){
indexCount[a[i]-1] = i+1;
check = false;
}else{
indexCount[a[i]-1] = (i+1) - indexCount[a[i]-1];
check = true;
}
if( check && indexCount[a[i]-1] < temp ){
duplicate = a[i];
temp = indexCount[a[i]-1];
}
}
return duplicate;
}
Instructions are:
Write a solution with O(n) time complexity and O(1) additional space complexity.
Given an array a that contains only numbers in the range from 1 to a.length, find the first duplicate number for which the second occurrence has the minimal index.
Example
For a = [2, 3, 3, 1, 5, 2], the output should be
firstDuplicate(a) = 3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3 has a smaller index than than second occurrence of 2 does, so the answer is 3.
For a = [2, 4, 3, 5, 1], the output should be
firstDuplicate(a) = -1.
Here is what I have. Runs in O(n) and uses O(1) space. Correct me if I'm wrong here.
Since my input cannot have a value that's more than the length, I can use mod operator for indexing on the same array and add the length to the value in index. As soon as I encounter a value that larger than the length, that means I've already incremented that before, which gives me the duplicate value.
public int firstDuplicate(int[] arr) {
int length = arr.length;
for (int i = 0; i < length; i++) {
int expectedIndex = arr[i] % length;
if (arr[expectedIndex] > length) {
return arr[i] > length ? arr[i] - length : arr[i];
} else {
arr[expectedIndex] += length;
}
}
return -1;
}
This answer is based on #Mehmet-Y's answer and all credit goes to Mehmet-Y. This version addresses the three issues I pointed out in the comments. I will delete this answer if the original gets corrected.
The general approach is to use the original array for storage instead of allocating a new one. The fact that no value may be less than one or greater than the length suggests that you can use the array as a set of indices to flag an element as "already seen" by either negating it or adding/subtracting the array length to/from it.
To achieve O(n) time complexity, you have to solve the problem in a fixed number of passes (not necessarily one pass: the number just can't depend on the size of the array).
But how do you decide which duplicate has the smallest second index? I would suggest using two different flags to indicate an index that is already seen vs. the second item in a duplicate pair. For this example, we can set the index flag by incrementing the elements by the length, and marking duplicates by negating them. You will need a second pass to find the first negagive in the array. You can also use that pass to restore the elements to their original values without sacrificing O(n) time complexity.
Here is a sample implementation:
int firstDuplicate(int[] a)
{
// assume all elements of a are in range [1, a.length]
// An assertion of that would not increase the time complexity from O(n)
int len = a.length;
for(int i = 0; i < len; i++) {
// a[i] may be > len, but not negative.
// Index of bin to check if this element is already seen.
flagIndex = (a[i] - 1) % len;
if(a[flagIndex] > len) {
// If already seen, current element is the second of the pair.
// It doesn't matter if we flag the third duplicate,
// just as long as we don't tag the first be accident.
a[i] = -a[i];
} else {
// Flag the element as "already seen".
// This can be done outside the else, but you might run
// into (more) overflow problems with large arrays.
a[flagIndex] += len;
}
}
// Search and stash index of first negative number
for(int i = 0; i < len; i++) {
if(a[i] < 0) {
return -a[i] % len;
}
}
// Nothing found, oh well
return -1;
}
If you want to take advantage of the second pass to restore the original values of the array, replace
for(int i = 0; i < len; i++) {
if(a[i] < 0) {
return -a[i] % len;
}
}
return -1;
with
int duplicate = -1;
for(int i = 0; i < len; i++) {
if(a[i] < 0) {
a[i] = -a[i];
if(duplicate == -1) {
duplicate = a[i] % len;
}
}
a[i] %= len;
}
return duplicate;

Removing an element from ArrayList

I have an ArrayList which contain 10 elements and a variable int = 12. Now I want to count how many elements are in array and if are less than 12 to start to count again from 0 and stop to index 2 and remove it, until I will have one element in my array. I tried the following:
int j = 12;
int l = 0;
// Here I check if j is less than array.size
while (j < array.size()) {
for (int i = 0; i < array.size(); i++) {
if (j == i + 1) {
array.remove(i);
}
}
}
// Here is for j greater than array.size
while (array.size() != 1) {
for (int i = 0; i < array.size(); i++) {
l = j - array.size();
if (l < array.size()) {
array.remove(l);
}
}
}
System.out.println(array);
UPDATE:
MyArray = {1,2,3,4,5,6,7,8,9,10};
int=12;
MyArray contain just 10 elements, but I want to delete the index with number 12, as long as index 12 does not exist I should start to count again from zero, and the number 12 is at index 2, That's why I should delete the index with number 2. The second iteration MyArray will contain just 9 elements, and again 12-9=3, I should delete the index with number 3, until I will have just one element in MyArray
Instead of looping twice through the array to remove the last n elements until the length of the list equals j, you could simply use:
while (j < array.size()) {
array.remove(j - 1);
}
If you always want to remove index 2, you could do:
while (array.size() >= 3) { // otherwise you will get a ArrayIndexOutOfBoundsException
array.remove(2);
}
However, you will have two elements left in your ArrayList instead of 1 (at index 0 and 1). You cannot delete ìndex 2 at that point, because it is not a valid index any longer.
Thus, you could either remove index 0/1 afterwards or what I think you want to achieve:
while (array.size() >= 2) { // otherwise you will get a ArrayIndexOutOfBoundsException
array.remove(1);
}
Then only one element will remain in your list at index 0.
Edit: for the update of your question it is
int originalSize = array.size();
while (array.size() >= originalSize - j) { // otherwise you will get a ArrayIndexOutOfBoundsException
array.remove(originalSize - j);
}
However, you will always be left with size - j items in your list. You cannot remove index 3, for example, until you have only one element in your list.
An answer to the updated question:
When you have a list of length 10 and you want to delete the "12th element" you can use the modulo operator:
ArrayList<...> someList = ...;
int toDelete = 12;
int deleteInRange = toDelete % someList.size();
someList.remove(deleteInRange);
The modulo operator will deliver the rest of the integerdivision 12 / 10 (toDelete % someList.size())
You can use this code snippet in a loop in order to remove multiple elements.
If you always want to remove index 2, you could do:
l = j - array.size();
Change this line as below:
int sum = 0;
sum = l - array.size();
if (sum > 0) {
array.remove(sum);
} else {
sum = array.size() - l;
array.remove(sum);
}

How to find the number of zero elements between sequential non-zero elements

I want to know how many zeros are between sequential non-zero elements in f array. This is how I do it:
int[] f = new int[]{0,0,3,0,0,1};
int start = 0, end = 0;
for (int i=0; i<f.length; i++)
{
if (f[i] != 0 && start == 0)
start=i;
else if (f[i] != 0 && start != 0)
end=i;
}
int cnt = (end-start-1)>=0 ? (end-start-1) : (start-end-1);
The answer is 2 zeros between 3 and 1.
However, in case of int[] f = new int[]{0,3,2,0,0,1} the answer is 3, which is not correct. It should be 2.
Update:
I want to count the number of zeros between LAST left-hand side non-zero element and FIRST right-hand side non-zero element.
Your logic of detecting when there are changes (from 0 to non-0 and from non-0 to 0 elements) is flawed.
You should look at the i and i-1 elements instead. Consider the following:
The start index should be when element i-1 is non-zero and element i is 0.
The end index should be when element i-1 is 0 and element i is non-0 and a start element was found (start > 0, this is to take into account the fact that the array can start with 0 and there were no start sequence).
The next thing to consider is that there may be multiple cases of 0's enclosed in non-0's in the array so each time we encounter an end element, we need to add this to a current count.
Putting this into code:
private static int countZeros(int[] f) {
int start = 0, end = 0, cnt = 0;
for (int i = 1; i < f.length; i++) {
if (f[i-1] != 0 && f[i] == 0) {
start = i;
} else if (f[i-1] == 0 && f[i] != 0 && start > 0) {
end = i;
cnt += end - start;
}
}
return cnt;
}
Some examples:
System.out.println(countZeros(new int[]{0,0,3,0,0,1})); // prints 2
System.out.println(countZeros(new int[]{3,0,0,1})); // prints 2
System.out.println(countZeros(new int[]{3,0,0,1,0})); // prints 2
System.out.println(countZeros(new int[]{3,0,0,1,0,1})); // prints 3
If you want the last 0s group, count backwards.
private static int countZeros(int[] f) {
for (int i=f.length-1; i>=0; i--){
if(f[i]!=0 && i>0 && f[i-1]==0){
i--;
int count=0;
while(i>=0 && f[i]==0){
i--;
count++;
}
if(i==0)
return null;
else
return count;
}
}
return null;
}
Your loops behaviour will have the following effect:
for (int i=0; i<f.length; i++)
{
if (f[i] != 0 && start == 0) //finds only first non-zero in whole array
start=i;
else if (f[i] != 0 && start != 0) //finds last non-zero in whole array
end=i;
}
But by taking the difference you include all non-zeros and zeros in the range. So you need a way to count only zeros between these to points, which is hard to add to the first loop because end will be changing. The easiest solution is to loop a second time from start to end and count the zeros:
int cnt = 0;
for(int i=start; i<end; i++)
if(f[i]==0)
cnt++;
This may not the most efficient solution, but it is a way to build upon your existing logic.

Remove every 3rd element in arraylist

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

Categories