How to extract longest consecutive sequence of integers from array in Java? - java

I want is to display all consecutive sequences from a given array of ints.
Finally I want to display the longest one with text.
What I tried
I sorted the array and found all sequences.
I stored the found sequences into a new ArrayList.
Below is only a small piece of code, because I know the rest doesn't work:
int[] myArray = {202,203,204,205,206, 100, 1, 3, 200, 2, 4, 201, 5};
ArrayList<Integer> secuence = new ArrayList<>();
Arrays.sort(myArray);
for (int i = 0; i < myArray.length - 1; i++) {
if ((myArray[i] + 1) == myArray[i + 1] || (myArray[i] - 1) == myArray[i - 1]) {
secuence.add(myArray[i]);
}
}
I tried many different ways, but can't figure out.

A couple remarks, suggestions:
As sort() sorts the array in increasing order, actually you do not have to check for decreasing elements
For finding the "anything"est thing, you need to store the "anything"est thing found so far, and a current candidate. This applies to finding largest element or longest sequence of consecutive elements too
For dealing with subparts of an array, it is not necessary to make an actual copy of the elements, it is enough to store beginning index and ending index or length.
Putting them together:
var myArray = [202,203,204,205,206, 100, 1, 3, 200, 2, 4, 201, 5];
myArray.sort((a,b)=>a-b);
console.log("Sorted array:",...myArray);
var longstart=0;
var longlength=0;
var currstart=0;
while(currstart<myArray.length){
var currlength=0;
while(currstart+currlength<myArray.length
&& myArray[currstart]+currlength==myArray[currstart+currlength])
currlength++;
if(currlength>longlength){
longlength=currlength;
longstart=currstart;
}
console.log("Sequence:",...myArray.slice(currstart,currstart+currlength));
currstart+=currlength;
}
console.log("Longest:",...myArray.slice(longstart,longstart+longlength));
This code is JavaScript so it can be run here, a Java variant (just with less printing) would look very similar:
int[] myArray = {202,203,204,205,206, 100, 1, 3, 200, 2, 4, 201, 5};
Arrays.sort(myArray);
int longstart=0;
int longlength=0;
int currstart=0;
while(currstart<myArray.length){
int currlength=0;
while(currstart+currlength<myArray.length
&& myArray[currstart]+currlength==myArray[currstart+currlength])
currlength++;
if(currlength>longlength){
longlength=currlength;
longstart=currstart;
}
currstart+=currlength;
}
for(int i=0;i<longlength;i++)
System.out.print((i==0?"Longest: ":", ")+myArray[longstart+i]);
The key thing is to have the check work with a growing distance, so the fixed [i]+1==[i+1] check in your initial code became [i]+distance==[i+distance].

I approached the solution as follows:
Data structures
a consecutive sequence (what we want to find) is a List of at least 2 consecutive Integers (pair)
to return all foundSequences you need one result List containing 0 or more Lists
to check for consecutive-ness you need the current and previous element
Algorithm
Logic applied (if):
Consecutive-ness is found if current == previous + 1, otherwise an existing consecutive sequence is broken
If a sequence has at least 2 elements, i.e. sequence.size() > 1, then it should be added to the result list (i.e. foundSequences)
Before the first element and after each broken sequence, the previous == null
After the last element there could be an open sequence with sequence.size() > 1. If so, then this sequence is not broken, but completed and should be added to the result list (i.e. foundSequences)
Iterating over elements (loop):
Use a for-each loop to process all elements of the (sorted!) array
The for-loop automatically fills the current element (iterating variable)
You must keep track of the previous element (thus initialized null before the loop). It must archive the current element of each loop, so we can compare the next element against it.
Unless the current element is not consecutive anymore (a break happened), then the previous will become null to start a fresh collection.
In case of a break the currently found sequence may be added to the result. Then the sequence needs to be reset to null to start a fresh collection.
After the last element was checked and the loop ended, there could be still a sequence (that was not yet broken). This needs to be added to the result.
8.
Source
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class ConsecutiveSequenceFinder {
private int[] unsortedNumbers;
public ConsecutiveSequenceFinder(int[] numbers) {
this.unsortedNumbers = numbers;
}
public int[] sorted() {
int[] sortedNumbers = Arrays.copyOf(this.unsortedNumbers, this.unsortedNumbers.length);
Arrays.sort(sortedNumbers);
return sortedNumbers;
}
public List<List<Integer>> findSequences() {
// one sequence is List of integers; thus list of sequences is list of list of integers
List<List<Integer>> foundSequences = new ArrayList<>();
// first we sort the array
int[] ascending = this.sorted();
// this working variable will hold the currently found sequence
List<Integer> sequence = new ArrayList<Integer>();
Integer previous = null;
System.out.println("Finding sequences ..");
for (int current : ascending) {
// check if current value is first or one more than (consecutive to) previous
if (previous == null || current == previous + 1) {
sequence.add(current);
previous = current;
} else {
System.out.printf("\tsequence of %d consecutive is broken at: %d\n", sequence.size(), current);
// if sequence found (at least a pair) then add
if (sequence.size() > 1) {
foundSequences.add(sequence);
}
// and finally prepare a new sequence, to collect fresh again
sequence = new ArrayList<>();
previous = null;
}
}
// if sequence left, then add
if (sequence.size() > 1) {
System.out.printf("\tsequence of %d consecutive was completed with last array element\n", sequence.size());
foundSequences.add(sequence);
}
return foundSequences;
}
public static void main (String[] args) throws java.lang.Exception {
// demo numbers
int[] values = {202,203,204,205,206, 100, 1, 3, 200, 2, 4, 201, 5};
// starting demo
System.out.println("Input: " + Arrays.toString(values));
ConsecutiveSequenceFinder finder = new ConsecutiveSequenceFinder(values);
System.out.println("Sorted: " + Arrays.toString(finder.sorted()));
List<List<Integer>> foundSequences = finder.findSequences();
System.out.println("Found sequences: " + foundSequences.size());
// print for each sequence the size and its elements
for (List<Integer> sequence : foundSequences) {
System.out.printf("\t %d elements: %s\n",sequence.size(), sequence.toString());
}
// check for each sequence if it is the longest
List<Integer> longestSequence = new ArrayList<>();
for (List<Integer> sequence : foundSequences) {
if (sequence.size() > longestSequence.size()) {
longestSequence = sequence;
}
}
System.out.printf("Longest sequence has %d elements: %s\n",longestSequence.size(), longestSequence.toString());
}
}
Actual Output
Input: [202, 203, 204, 205, 206, 100, 1, 3, 200, 2, 4, 201, 5]
Sorted: [1, 2, 3, 4, 5, 100, 200, 201, 202, 203, 204, 205, 206]
Finding sequences ..
sequence of 5 consecutive is broken at: 100
sequence of 7 consecutive was completed with last array element
Found sequences: 2
5 elements: [1, 2, 3, 4, 5]
7 elements: [200, 201, 202, 203, 204, 205, 206]
Longest sequence has 7 elements: [200, 201, 202, 203, 204, 205, 206]
Process finished with exit code 0

Related

Getting elements from an array where next element greater than previous by 1

I have an array:
int[] arr = {-4, -2, -1, 0, 1, 3, 4, 5, 6, 9, 10, 12, 13, 14, 18};
The array is ordered in ascending order.
The main idea is to get elements and group them, where next element is greater than a previous by 1. The minimum length of such elements should be equal 3.
In output, I have to get a string:
"-4, (-2-1), (3-6), 9, 10, (12-14), 18"
The first interval is:
-2, -1, 0, 1 - it should looks like range i.e -2-1
The next interval is:
3, 4, 5, 6 - it should looks like range i.e 3-6
9, 10 - the length is less than 3
So the last interval is:
12, 13, 14 it should looks like range i.e 12-14
this answer was pre-edit.
You are printing input[i] but you are expecting the values in input[i] - 1
when you run this in the debugger you can see it finds -1 (which has -2 before it, and equals -2 + 1). You then print the -1 you found.
If you want the output to contain the -2 , you should print input[i - 1]
post-edit:
you have grouped elements by braces which means you are looking for a sequence. This will require you to keep the start number somewhere. the code you originally posted (simple loop that checks left) will need a bit more work.
In rough terms:
if (continuing a range)
if(this number is still in range / +1) continue
else: stop the range and print it (start point plus current -1). if current -1 is the start point, don't use braces and range indicator. if it is different use braces and - between start and end)
else
start a range. (keep track of the number you are on and continue.
that's what you need in pseudocode
Algorithm
You could loop through the array.
If found consecutive number, add it to a group (e.g. List).
If group satisfies minimum length (e.g. 3) then add it to output formatted as range (and clear the group).
If no consecutive number, just add it to output.
Code
public static String formatAsRange(List<Integer> list) {
return String.format("(%d-%d)", list.get(0), list.get(list.size()-1));
}
public static String consecutiveElements(int[] array, int minGroupLength) {
StringBuilder sb = new StringBuilder();
List<Integer> group = new ArrayList<>();
for(int i = 0; i < array.length; i++) {
if (i == 0 || array[i] == array[i-1] + 1) {
group.add(array[i]);
} else {
if (group.size() >= minGroupLength) {
sb.append(formatAsRange(group)).append(',');
} else {
var csv = group.stream().map(String::valueOf).collect(Collectors.joining(","));
sb.append(csv).append(',');
}
group.clear();
sb.append(array[i]).append(',');
}
}
return sb.toString();
}
For your input it prints:
-4,-2,(-1-1),3,(4-6),9,10,12,13,14,18,
See the demo on IDEone.
To do
So there is still something to fix. For example
expected range 12-14 is missing
expected range -2-1 is not complete with -2, (-1-1)
expected range 3-6 is not complete with 3, (4-6)
the last comma can be removed
can add a space following each comma

Removing Duplicate Integers in an ArrayList

I see a lot of posts with the same topic (mostly with Strings) but haven't found the answer to my question. How would I remove duplicate integers from an ArrayList?
import java.util.*;
public class ArrayList2 {
public static ArrayList<Integer> removeAllDuplicates(ArrayList<Integer> list) {
Collections.sort(list);
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == list.get(i + 1)) {
list.remove(i);
}
}
return list;
}
}
This is the start of my code, the only problem that has arised is that if there are 3 integers with the same value, it only removes one of them. If I put in 4, it removes two of them. PLEASE NO HASHING!!!
The ArrayList and the output when I run it:
List: [-13, -13, -6, -3, 0, 1, 1, 1, 5, 7, 9]
Duplicates Removed: [-13, -6, -3, 0, 1, 1, 5, 7, 9]
This is my first time using this website, so please let me know if I'm doing something wrong with formatting/if there's already an answer to my question that I missed.
The specific reason why your removeAllDuplicates function doesn't work is that you are still iterating after a successful comparison. If you iterate only when list.get(i) != list.get(i + 1), you will get rid of all the duplicates.
public static ArrayList<Integer> removeAllDuplicates(ArrayList<Integer> list) {
Collections.sort(list);
int i = 0;
while(i < list.size() - 1) {
if (list.get(i) == list.get(i + 1)) {
list.remove(i);
} else {
i++;
}
}
return list;
}
It's worth noting that the above function is not as fast as it could be. Though the iteration runs quickly enough, the most significant step will be the sort operation (O(n log n)).
To avoid this extra time complexity, consider using a HashSet instead of an ArrayList (if it still fits within the constraints of your problem).
Other people have "answered" the basic issue, of the if statement skipping over elements because the for-loop is incrementing the index position, while the size of the array is shrinking.
This is just "another" possible solution. Personally, I don't like mutating Lists in loops and prefer to use iterators, something like...
Collections.sort(list);
Iterator<Integer> it = list.iterator();
Integer last = null;
while (it.hasNext()) {
Integer next = it.next();
if (next == last) {
it.remove();
}
last = next;
}
Still, I think some kind of Set would be a simpler and easier solution (and since you'd not have to sort the list, more efficient ;))
This assumes that you cannot use a set ("Please No hashing!!!") for a reason such as homework.
Look what happens when you remove a duplicate. Let's say that the dupe you're removing is the 1st of 3 consecutive equal numbers.
v
-13, -6, -3, 0, 1, 1, 1, 5, 7, 9
Here i is 4 to refer to the first of the 3 1 values. When you remove it, all subsequent elements get shifted down, so that the second 1 value now takes the place of the first 1 value at index i = 4. Then the current iteration ends, another one begins, and i is now 5.
v
-13, -6, -3, 0, 1, 1, 5, 7, 9
But now i is referring to the second of the two 1 values left, and the next element 5 isn't equal, so no dupe is found.
Every time you find a duplicate, you must decrease i by 1 so that you can stay on the first element that is a duplicate, to catch 3 or more duplicates in a row.
v
-13, -6, -3, 0, 1, 1, 5, 7, 9
Now consecutive elements still match, and another 1 value will get removed.
You'd want to have a double for loop as you dont want to check the only the next index but all indexes. As well as remember when you remove a value you want to check that removed value again as it could of been replaced with another duplicate value.

Tough recursive task

I've been struggle with question I'm trying to solve as part of test preparation, and I thought I could use your help.
I need to write a Boolean method that takes array with integers (positive and negative), and return true if the array can be split to two equals groups, that the amount of every group's numbers is equals to the other group.
For exmaple, for this array:
int[]arr = {-3, 5, 12, 14, -9, 13};
The method will return true, since -3 + 5 + 14 = 12 + -9 + 13.
For this array:
int[]arr = {-3, 5, -12, 14, -9, 13};
The method will return false since even though -3 + 5 + 14 + -12 = -9 + 13, the amount of numbers in every side of the equation isn't equals.
For the array:
int[]arr = {-3, 5, -12, 14, -9};
The method will return false since array length isn't even.
The method must be recursive, overloading is allowed, every assist method must be recursive too, and I don't need to worry about complexity.
I've been trying to solve this for three hours, I don't even have a code to show since all the things I did was far from the solution.
If someone can at least give me some pseudo code it will be great.
Thank you very much!
You asked for pseudocode, but sometimes it's just as easy and clear to write it as Java.
The general idea of this solution is to try adding each number to either the left or the right of the equation. It keeps track of the count and sum on each side at each step in the recursion. More explanation in comments:
class Balance {
public static void main(String[] args) {
System.out.println(balanced(-3, 5, 12, 14, -9, 13)); // true
System.out.println(balanced(-3, 5, -12, 14, -9, 13)); // false
}
private static boolean balanced(int... nums) {
// First check if there are an even number of nums.
return nums.length % 2 == 0
// Now start the recursion:
&& balanced(
0, 0, // Zero numbers on the left, summing to zero.
0, 0, // Zero numbers on the right, summing to zero.
nums);
}
private static boolean balanced(
int leftCount, int leftSum,
int rightCount, int rightSum,
int[] nums) {
int idx = leftCount + rightCount;
if (idx == nums.length) {
// We have attributed all numbers to either side of the equation.
// Now check if there are an equal number and equal sum on the two sides.
return leftCount == rightCount && leftSum == rightSum;
} else {
// We still have numbers to allocate to one side or the other.
return
// What if I were to place nums[idx] on the left of the equation?
balanced(
leftCount + 1, leftSum + nums[idx],
rightCount, rightSum,
nums)
// What if I were to place nums[idx] on the right of the equation?
|| balanced(
leftCount, leftSum,
rightCount + 1, rightSum + nums[idx],
nums);
}
}
}
This is just a first idea solution. It's O(2^n), which is obviously rather slow for large n, but it's fine for the size of problems you have given as examples.
The problem described is a version of the Partition problem. First note that your formulation is equivalent to deciding whether there is a subset of the input which sums up to half of the sum of all elements (which is required to be an integral number, otherwise the instance cannot be solved, but this is easy to check). Basically, in each recursive step, it is to be decided whether the first number is to be selected into the subset or not, resulting in different recursive calls. If n denotes the number of elements, there must be n/2 (which is required to be integral again) items selected.
Let Sum denote the sum of the input and let Target := Sum / 2 which in the sequel is assumed to be integral. if we let
f(arr,a,count) := true
if there is a subset of arr summing up to a with
exactly count elements
false
otherwise
we obtain the following recursion
f(arr,a,count) = (arr[0] == a && count == 1)
||
(a == 0 && count == 0)
if arr contains only one element
f(arr\arr[0], a, count)
||
f(arr\arr[0], a - arr[0], count -1)
if arr contains more than one element
where || denotes logical disjuction, && denoted logical conjunction and \ denotes removal of an element.
The two cases for a non-singleton array correspond to chosing the first element of arr into the desired subset or its relative complement. Note that in an actual implementation, a would not be actually removed from the array; a starting index, which is used as an additional argument, would be initialized with 0 and increased in each recursive call, eventually reaching the end of the array.
Finally, f(arr,Target,n/2) yields the desired value.
Your strategy for this should be to try all combinations possible. I will try to document how I would go about to get to this.
NOTE that I think the requirement: make every function use recursion is a bit hard, because I would solve that by leaving out some helper functions that make the code much more readable, so in this case I wont do it like that.
With recursion you always want to make progression towards a final solution, and detect when you are done. So we need two parts in our function:
The recursive step: for which we will take the first element of the input set, and try what happens if we add it to the first set, and if that doesn't find a solution we'll try what happens when we add it to the second set.
Detect when we are done, that is when the input set is empty, in that case we either have found a solution or we have not.
A trick in our first step is that after taking the first element of our set, if we try to partition the remainder, we don't want the 2 sets being equal anymore, because we already assigned the first element to one of the sets.
This leads to a solution that follows this strategy:
public boolean isValidSet(MySet<int> inputSet, int sizeDifferenceSet1minus2)
{
if (inputSet.isEmpty())
{
return sizeDifferenceSet1minus2== 0;
}
int first = inptuSet.takeFirst();
return isValidSet(inputSet.copyMinusFirst(), sizeDifferenceSet1minus2+ first)
|| isValidSet(inputSet.copyMinusFirst(), sizeDifferenceSet1minus2+ -1 * first);
}
This code requires some help functions that you will still need to implement.
What it does is first test if we have reached the end condition, and if so returns if this partition is successful. If we still have elements left in the set, we try what happens if we add it to the first set and then what happens when adding it to the second set. Note that we don't actually keep track of the sets, we just keep track of the size difference between set 1 minus 2, decreasing the (but instead you could pass along both sets).
Also note that for this implementation to work, you need to make copies of the input set and not modify it!
For some background information: This problem is called the Partition Problem, which is famous for being NP-complete (which means it probably is not possible to solve it efficiently for large amounts of input data, but it is very easy to verify that a partitioning is indeed a solution.
Here is a verbose example:
public static void main(String[] args)
{
System.out.println(balancedPartition(new int[] {-3, 5, 12, 14, -9, 13})); // true
System.out.println(balancedPartition(new int[] {-3, 5, -12, 14, -9, 13})); // false
System.out.println(balancedPartition(new int[] {-3, 5, -12, 14, -9})); // false
}
public static boolean balancedPartition(int[] arr)
{
return balancedPartition(arr, 0, 0, 0, 0, 0, "", "");
}
private static boolean balancedPartition(int[] arr, int i, int groupA, int groupB, int counterA, int counterB, String groupAStr, String groupBStr)
{
if (groupA == groupB && counterA == counterB && i == arr.length) // in case the groups are equal (also in the amount of numbers)
{
System.out.println(groupAStr.substring(0, groupAStr.length() - 3) + " = " + groupBStr.substring(0, groupBStr.length() - 3)); // print the groups
return true;
}
if (i == arr.length) // boundaries checks
return false;
boolean r1 = balancedPartition(arr, i + 1, groupA + arr[i], groupB, counterA + 1, counterB, groupAStr + arr[i] + " + ", groupBStr); // try add to group 1
boolean r2 = balancedPartition(arr, i + 1, groupA, groupB + arr[i], counterA, counterB + 1, groupAStr, groupBStr + arr[i] + " + "); // try add to group 2
return r1 || r2;
}
Output:
-3 + 5 + 14 = 12 + -9 + 13 // one option for the first array
12 + -9 + 13 = -3 + 5 + 14 // another option for the first array
true // for the first array
false // for the second array
false // for the third array

arraylist is always created with a constant capacity

I am trying to compute pascal's triangle given a row number. I am using recursion.
My code is below:
public static List<Integer> getRow(int rowIndex) {
if (rowIndex == 1){
List <Integer> list = new ArrayList(rowIndex+1);
list.add(1);
return list;
}
else{
List<Integer> oldList = getRow(rowIndex -1);
List <Integer> list = new ArrayList(rowIndex+1);
int temp = 0;
list.add(0,1);
list.add(list.size()-1,1);
System.out.println("rowIndex "+rowIndex);
for (int i = 1; i < list.size()-1; i ++){
temp = oldList.get(i) + oldList.get(i-1);
list.add(i,temp);
}
return list;
}
}
It always returns [1,1] regardless of what row I am trying to get. I tried inserting print statements. I noticed the size of list is always 2 regardless of what rowIndex is.
List <Integer> list = new ArrayList(rowIndex+1);
Is the line above not the correct way to create an ArrayList? Seems like my arraylist always has size = 2;
you misunderstand how ArrayLists do work and you really should read the Javadoc.
In short, the constructor's parameter defines the initial size of the ArrayList in memory, not the max size. If you instantiate a new ArrayList<Integer>(2)it only means that the jvm allocates upfront enough space for two Integers, and that when you add a third element then the jvm will grow the size of the ArrayList in order to allow you to add more elements.
Further, you can access an ArrayList position with get() only if an element has been added at this position.
Finally, keep in mind that add at a specific position shifts right all elements. Thus if you add(10,1) then add(2,4), your first add will be shifted right.
Back to your question, if you absolutely want to use an ArrayList and not an array, you have to initialize your ArrayList with the right size, then set values at the right positions.
Here is a working solution :
// the method with your algorithm which has been slightly modified
public static List<Integer> getRow(final int rowIndex) {
// notice that I call a helper method which initialises correctly the ArrayList
final List<Integer> list = init(rowIndex);
if (rowIndex == 1) {
// notice that I set the value at a given position
// I can only do it because I initialised all values to 0 first
list.set(0, 1);
} else {
final List<Integer> previousRowList = getRow(rowIndex - 1);
// again, I set values...
list.set(0, 1);
list.set(rowIndex - 1, 1);
for (int i = 1; i < (list.size() - 1); i++) {
// set again...
list.set(i, previousRowList.get(i - 1) + previousRowList.get(i));
}
}
// lets print out the row
System.err.println(list);
// then return it
return list;
}
public static List<Integer> init(final int size) {
// passing the size is overkill, but well...
final List<Integer> list = new ArrayList<Integer>(size);
// fill the ArrayList with zeros
for (int i = 0; i < size; i++) {
list.add(i, 0);
}
// then return it
return list;
}
public static void main(final String[] args) {
getRow(Integer.parseInt(args[0]));
}
If you run it you'll get a (not so nice, but working) Pascal's triangle. Here follows the result if you want 11 rows :
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
[1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]
Hope it helps !
I think you're miss-interpreting the data structures.
And array list is a LIST implemented on top of an array. Setting the size of the array in the constructor is a way to give control to the developer for the initial size of the array (This is rarely necessary as the class manages the array size itself--so just leave out this argument). So the size of an array list is actually the size of the list, which is the number of elements, not the number of buckets in the underlying array which is specified in the constructor.
If you know the size of the array you want, and you want to get and add at specific locations, use a standard array, not an array list.
However, I think your code will work if you move
list.add(list.size()-1,1);
to after your for-loop (I'm actually surprised it doesn't throw an index out of bounds exception). And since you're going left to right, none of your adds need an index specified, since it'll just add it to the end of the existing list.

Removing pairs of elements in an Arraylist in Java

I know similar questions have been asked before, but they typically remove all of the specified element from an Arraylist.
What I need to do, is remove pairs of values from my ArrayList (if a number occurs 3 times, it will remove 2 copies of that element and leave 1 of them). More generally, if a number occurs an odd number of times leave 1, if a number occurs an even number of times remove them all. Thus, if my Arraylist was something like this
[5, 4, 3, 3, 2, 1, 2, 3, 1],
the output would be
[5, 4, 3]
Since the number "2" appears twice, it is complete removed. Same with the number "1". But since the number "3" appears three times, it leaves one of them in the ArrayList, because I only want to remove the numbers in pairs.
I don't care at all about the ordering, as I'm going to reorder it anyways.
Does anyone have any suggestions on doing this? I think I could use a for loop that compares each value over and over, but it seems inefficient, so I was curious if there would be a better way.
Thank you!
If you're allowed to sort the arraylist, this becomes pretty simple.
public void removePairedElements(ArrayList<Integer> a){
Collections.sort(a); //Sort a
int i = 0;
while(i < a.size() - 1){
//Check if i and i+1 are the same element. If so, remove both
if(a.get(i).equals(a.get(i+1))){
//Remove i twice - effectively removes i and i+1
a.remove(i);
a.remove(i);
//Move i *back* one index, which is equivalent to
//moving forward one because we just removed two elements.
//Prevent i from becoming negative though.
i = Math.max(0, (i - 1));
}
else{
i++;
}
}
}
O(n log n) time and O(1) space. Probably the cleanest answer. If you aren't allowed to change the ordering of the arraylist you'd have to do something else, but otherwise this should work.
You can use a Map as a helper.
iterate over the ArrayList
Lets say the i'th element of the list contains the number n.
If map.containsKey(n), map.get(n) is the location in the list of the previous occurrence of n.
remove both the i'th element and the map.get(n)'th element from the list.
remove the key n from the map.
Else
map.put (n,i)
Implementation note :
Don't use an enhanced for loop to iterate over the list (since it doesn't allow removal of elements). Iterate over the indices of the list. This will allow you to remove the elements by their index (but remember that when you remove the i'th element, the previous i+1 element becomes the new i'th element).
I think your best bet would be to sort the list.
Then, going backwards, remove ints if you see the same one while keeping track of the total count of current ints.
If you see an even total count, you will NOT remove the last occurrence.
If you see an odd total count, you will remove the last occurence.
public void removePairElementsFrom(Arraylist<Integer> myArrayList)
{
if (myArrayList == null)
{
return null;
}
int arrayLength = myArrayList.size();
if (arrayLegnth == 1)
{
return myArrayList;
)
Collections.sort(myArrayList);
int lastSeenInt = myArrayList.get(arrayLength - 1);
int lastSeenIntCount = 1;
for (int i = arrayLength - 2; i >= 0; --i)
{
if (myArrayList[i] == lastSeenInt)
{
myArrayList.remove(i+1);
++lastSeenIntCount;
}
else
{
if ((lastSeenIntCount % 2) == 0)
{
myArrayList.remove(i+1);
}
lastSeenInt = myArrayList.get(i);
lastSeenIntCount = 1;
}
}
if ((lastSeenIntCount % 2) == 0)
{
myArrayList.remove(0);
}
}
Enjoy :)
Write a method removeBadPairs that accepts an ArrayList of integers and removes any adjacent pair
of integers in the list if the left element of the pair is larger than the right element of the pair. Every pair's
left element is an even-numbered index in the list, and every pair's right element is an odd index in the list.
For example, suppose a variable called list stores the following element values:
[3, 7, 9, 2, 5, 5, 8, 5, 6, 3, 4, 7, 3, 1]
We can think of this list as a sequence of pairs: (3, 7), (9, 2), (5, 5), (8, 5), (6, 3), (4, 7), (3, 1). The pairs (9,
2), (8, 5), (6, 3), and (3, 1) are "bad" because the left element is larger than the right one, so these pairs
should be removed. So the call of removeBadPairs(list); would change the list to store the following
element values:
[3, 7, 5, 5, 4, 7]
If the list has an odd length, the last element is not part of a pair and is also considered "bad;" it should
therefore be removed by your method.
If an empty list is passed in, the list should still be empty at the end of the call. You may assume that the
list passed is not null. You may not use any other arrays, lists, or other data structures to help you solve
this problem, though you can create as many simple variables as you like.
You will get an error if you start from the start of the list using For loop due to an iterator. So I have an alternate way.
class RemoveBadPairs {
Public Static void main() {
ArrayList numbersList = new ArrayList();
numberslist={3,7,9,2,5,5,8,5,6,3,4,7,3,1,7};
System.out.println("Original List...");
for (e in : numbersList) {
System.out.print("{0},", e);
}
if (((numbersList.Count % 2)!= 0)) {
numbersList.RemoveAt((numbersList.Count - 1));
}
for (int i = (numbersList.Count - 1); (i <= 0); i = (i + -2)) {
if ((numbersList[i] < numbersList[(i - 1)])) {
numbersList.RemoveRange((i - 1), 2);
}
}
System.out.println("Final List...");
for (e in : numbersList) {
System.out.print(","+ e);
}
}
}
I hope this will work.

Categories