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.
Related
I'm making a method called fillList. The method will require an arrayList in order to work and the output will be void.
What the method is supposed to do is to fill the gaps between the numbers of the List.
Example:
Input:
4 8 5 9
Output:
4 5 6 7 8 7 6 5 6 7 8 9
The code I have so far is this:
public static void fillList(ArrayList<Integer> List) {
for(int i = 0; i < List.size(); i++) {
if(List.get(i) < List.get(i+1) ) {
List.add(List.get(i+1));
} else if(List.get(i) > List.get(i+1)) {
List.add(List.get(i-1));
}
}
}
My idea was to add 1 to the value of the first element if the first element was less than the second element in the List. For example if the first element is 4 then the code would add a 5 to the list and stop once the number added was equal to one less than the second element. And basically do the opposite if the first element was more than the second element.
I don't know how to stop this loop until the numbers that are being added reach the second element of the list. I am not confident about my code as well I'm pretty sure I am making an error I'm not seeing.
Great question, I think you can learn alot by working this one out and really understanding every single line. I have made a litte illutration for you, to visualize the problem better. Hope this can help you. General tips:
variables are always lowercase by convention so write list instead of List
list.add(5) will add the number 5 to the end of your ArrayList. You can use list.add(4, 5) for example to insert the number 5 into the array position 4.
To update the list while iterating over its indices, you can use method List.add(int index, E element), which expects an index and a new element to insert.
While iterating, you need to compare two adjacent elements and insert a new one under the following conditions:
Left element is less than the right one and difference between them is greater than 1. A new element should be equal left + 1.
Left element is greater than the right one, and they differ more than by 1. A new element should be equal left - 1.
Also have a look at the nicely illustrated answer by #yezper. And as a general advice: draw before coding in order to understand the algorithm better.
That's how implementation might look like:
public static void fillList(List<Integer> list) {
for (int i = 0; i < list.size() - 1; i++) {
int left = list.get(i);
int right = list.get(i + 1);
if (left < right && left + 1 != right) {
list.add(i + 1, left + 1);
} else if (left > right && left - 1 != right) {
list.add(i + 1, left - 1);
}
}
}
main()
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>(List.of(4, 8, 5, 9));
fillList(list1);
System.out.println(list1);
}
Output:
[4, 5, 6, 7, 8, 7, 6, 5, 6, 7, 8, 9]
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.
I have an integer array of size 4. I am adding elements to it via the add method. This is as an unsorted array. I am sorting it via the sort method shown in the code below. The sort method places the smallest number in the position a[0]. When I try to add elements after I call the sort method I always get a return value of 0. Is there a way around this?
import java.util.Arrays;
public class Scrap {
private static int[] array = new int[4];
private static int i = 0;
public static void main(String[] args) {
Scrap pq = new Scrap();
pq.add(4);
pq.insert(3);
pq.add(5);
pq.sort();// smallest to largest sort method.
// System.out.println(array[0]);
pq.insert(1);
pq.sort();
int test = pq.Minimum();
System.out.println("The smallest element of the array is " + test);
pq.sort();
}
//
public void add(int input) {
insert(input);
}
// Method to insert number into the array.
public void insert(int input) {
array[i] = input;
i++;
}
// Finding smallest number of the array.
public int Minimum() {
int a = array[0];
return a;
}
// Sorts the array from smallest to largest integer
public void sort() {
int first, temp;
for (int i = array.length - 1; i > 0; i--) {
first = 0;
for (int j = 1; j <= 1; j++) {
if (array[j] > array[first])
first = j;
}
temp = array[first];
array[first] = array[i];
array[i] = temp;
}
}
public int remove() {
return delete();
}
public int delete() {
return remove();
}
// Method to convert the array into a string for output
}
The problem in a nutshell:
You start with an array of length 4.
At this point the array contains 4 zeros, that is: [0, 0, 0, 0]
You add 4, 3, and 5. These operations update the content of the array to [4, 3, 5, 0].
You sort the array. This should change the content of the array to [0, 3, 4, 5]. In fact it changes to [0, 5, 3, 4], which means your implementation of sort is clearly broken.
You probably didn't expect the 0 value to move. You can fix this by sorting only the first 3 values. (And, of course, you should also fix your implementation of sort.)
Then when you insert 1, the program updates the value at index 3, so the content changes to [0, 5, 3, 1].
If you implement the fix I suggested above, and sort only the first size elements, then the content after the first call to sort should become [3, 4, 5, 0], and the content after the insert 1 should become [3, 4, 5, 1]. And when you sort that again, the content should become [1, 3, 4, 5] and the smallest value will be 1 as expected, instead of 0.
More concretely:
First of all, change private static int i = 0; to private int size = 0;. The name i is extremely inappropriate here, and will surely confuse you. size is appropriate. It also doesn't make sense to make it static, so I suggest to drop that keyword.
Fix the implementation of sort. There are many basic sorting algorithms that are easy to implement. In the implementation, instead of going until array.size, go until size. Do you see the difference? size is the field in Scrap, essentially it's the number of elements you added using the add or insert methods.
Some cleaning up would be good too:
Delete the add method and rename insert to add.
Delete the remove and delete methods. They are not used, and you will get a stack overflow if you try to use them as they are now (the methods call each other, forever)
Look at the content of the array after each step in the program.
After Scrap pq is created, this is the content of its array:
[0, 0, 0, 0]
Then a couple of modifications:
pq.add(4);
pq.insert(3);
pq.add(5);
The content at this point:
[4, 3, 5, 0]
So far so good.
Then you sort it:
pq.sort();
The content at this point:
[0, 5, 3, 4]
Ouch. The sort implementation doesn't work very well, does it. But let's ignore that for now. Next step:
pq.insert(1);
The content at this point:
[0, 5, 3, 1]
None of this behavior makes sense, probably this is not how you intended the program to work. Review the program, verify the content after each step. Do not proceed to the next step until the current step is working correctly.
I am assuming that you will be using a correct sort method (because, this is not correct, you can use Arrays.sort). But still with a correct sort, there is a logical problem in your code.
At the beginning, the array contains all 0s. After adding the first 3 int, when you call the sort method, the array contains the values in following order:
0,3,4,5
Note that, the value of i is not changed. At this state the value of i is 3. So when you insert 1, the new values become
0,3,4,1
So after sorting again, the values of arrays become
0,1,3,4
So obviously the minimum will retrun 0
I don't think that is the most effective way to sort an array. It is possible to do this with just 1 for loop. Try this to sort your array from smallest to largest.
int temp;
for(int i=0;i<array.length-1;i++){
if(array[i]>array[i+1]){
temp=array[i];
array[i]=array[i+1];
array[i+1]=temp;
i=-1;
}
}
The problem is given an unsorted array, give subsets of array that can produce target sum:
For eg:
target = 15
data = {3,4,5,7,1,2,9};
Expected results (note the results are sorted for simplicity. not a requirement) :
[1, 2, 3, 4, 5]
[1, 2, 3, 9]
[1, 2, 5, 7]
[1, 3, 4, 7]
[1, 5, 9]
[2, 4, 9]
[3, 5, 7]
Here is my naive approach to this problem - simple and brute force.
public static void naiveSubset(int[] arr, int target){
int sum=0;
List<Integer> result = new ArrayList<>();
for (int i=0; i< arr.length;i++){
sum =arr[i];
result.add(arr[i]);
for (int j=0;j<arr.length;i++){
if (sum==target){
System.out.println(result);
result.clear();
break;
}
else if (i!=j && sum+arr[j] <= target){
sum+=arr[j];
result.add(arr[j]);
}
}
}
}
For some reasons, I am not expecting the results. I tried browsing through the code to dig out any issues. But I could not find any. please algo experts, point me in correct direction!!
The results I get (for same input as above)
[3, 3, 3, 3, 3]
[9, 3, 3]
Your solution is wrong because it's a greedy approach. It decides if you should add a number or not based on the fact that adding it does not violate the sum, at the moment.
However, this greedy approach does not work, with a simple example of the following array: [1,9,6,5] and with sum=11.
Note that for any element you choose in the outer loop, next you will add 1 to the current set. But that will deny you the possibility to get the sum of 5+6.
Once you choose 5, you start adding number, starting with '1', and adding it. Once it is added - you will never get the correct solution.
Also note: Your double loop approach can generate at most O(n^2) different subsets, but there could be exponential number of subsets - so something must be wrong.
If you want to get all possible subsets that sum to the given sum, you can use a recursive solution.
At each step "guess" if the current element is in the set or not, and recurse for both options for the smaller problem - if the data is in the set, or if it's not.
Here is a simple java code that does it:
public static void getAllSubsets(int[] elements, int sum) {
getAllSubsets(elements, 0, sum, new Stack<Integer>());
}
private static void getAllSubsets(int[] elements, int i, int sum, Stack<Integer> currentSol) {
//stop clauses:
if (sum == 0 && i == elements.length) System.out.println(currentSol);
//if elements must be positive, you can trim search here if sum became negative
if (i == elements.length) return;
//"guess" the current element in the list:
currentSol.add(elements[i]);
getAllSubsets(elements, i+1, sum-elements[i], currentSol);
//"guess" the current element is not in the list:
currentSol.pop();
getAllSubsets(elements, i+1, sum, currentSol);
}
Note that if you are looking for all subsets, there could be exponential number of those - so an inefficient and exponential time solution is expected.
If you are looking for finding if such a set exist, or finding only one such set, this can be done much more efficiently using Dynamic Programming. This thread explains the logic of how it can be done.
Note that the problem is still NP-Hard, and the "efficient" solution is actually only pseudo-polynomial.
I think the major issue in your previous approach is that simply doing loops based upon the input array will not cover all the combinations of numbers matching the target value. For example, if your major loop is in ith, and after you iterate through the jth element in your secondary loop, your future combination based on what you have collected through ith element will never include jth one anymore. Intuitively speaking, this algorithm will collect all the visible combinations through numbers near each other, but not far away from each other.
I wrote a iterative approach to cope with this subset sum problem through C++ (sorry, not have a java environment at hand:P), the idea is basically the same as the recurrsive approach, which means you would record all the existing number combinations during each iteration in your loop. I have one vector<vector> intermediate used to record all the encountered combination whose value is smaller than target, and vector<vector> final used to record all the combinations whose sum is equal to target.
The detailed explanation is recorded inline:
/* sum the vector elements */
int sum_vec(vector<int> tmp){
int sum = 0;
for(int i = 0; i < tmp.size(); i++)
sum += tmp[i];
return sum;
}
static void naiveSubset(vector<int> arr, int target){
/* sort the array from big to small, easier for us to
* discard combinations bigger than target */
sort(arr.begin(), arr.end(), greater<int>());
int sum=0;
vector<vector<int> > intermediate;
vector<vector<int> > final;
for (int i=0; i< arr.size();i++){
int curr_intermediate_size = intermediate.size();
for(int j = 0; j < curr_intermediate_size; j++){
int tmpsum = sum_vec(intermediate[j]);
/* For each selected array element, loop through all
* the combinations at hand which are smaller than target,
* dup the combination, put it into either intermediate or
* final based on the sum */
vector<int> new_comb(intermediate[j]);
if(tmpsum + arr[i] <= target){
new_comb.push_back(arr[i]);
if(tmpsum + arr[i] == target)
final.push_back(new_comb);
else
intermediate.push_back(new_comb);
}
}
/* finally make the new selected element a separate entry
* and based on its value, to insert it into either intermediate
* or final */
if(arr[i] <= target){
vector<int> tmp;
tmp.push_back(arr[i]);
if(arr[i] == target)
final.push_back(tmp);
else
intermediate.push_back(tmp);
}
}
/* we could print the final here */
}
Just wrote it so please bear with me if there is any corner case that I did not consider well. Hope this helps:)
It's an array of integers.
It was created this way:
No element is repeated. Every time an element is added, its number is the next available integer, from 0 onwards. This way, if you add 6 elements in a row, they will be 0, 1, 2, 3, 4, 5, in that order. If you delete an element, the array shrinks, and a 'hole' is left between two of the elements, they are no longer consecutive because of that gap: 0, 1, 3, 4, 5. Then comes the problem: if you add a new element, it gets added to the end, but has the next available integer. So, the array is now 0, 1, 3, 4, 5, 2. It needs to be sorted, so the 2 can occupy its place between the 1 and the 3.
What is the best way to do it? I have thought of several methods. The list is nearly ordered, and it has the property that, when it is ordered, every element is equal to or greater than its index in the array. I am currently doing a bubble sort (don't laugh), i think quick sort is overkill, i dont want to go recursive or use temporary arrays, and i dont want to change the add-element method (which adds the element at the end), so it must be sorted immediately after adding an element (so only the last element is out of place)
Take the last element and do a insertion sort.
Maybe you should look at the idea of Insertion Sort.
You do not need to sort the whole list, just insert the last element in order:
int pos = array.length - 1:
while (pos > 0 && array[pos] < array[pos - 1]) {
tmp = array[pos - 1];
array[pos - 1] = array[pos];
array[pos] = tmp;
pos--;
}
What about using a java.util.BitSet instead? You'd get constant-time insertion and removal (finding the first free place will still take O(n) though). And with nextSetBit, you can iterate over the set in ascending order. With nextClearBir(), finding the first unused index becomes trivial, too.
//based on gpeche's code
int pos = array.length - 1;
int val = array[pos];
while (pos > 0 && array[pos-1] > val) {
array[pos] = array[pos - 1];
pos--;
}
array[pos] = val;
Are you constrained to use an array? If not, then just use a TreeSet. Why write your own sort algorithm when you can make use of standard libraries that perform this function already? It has guaranteed O(log(n)) time for insertions.
import java.util.TreeSet;
TreeSet<Integer> sortedSet = new TreeSet<Integer>();
// Add integers as needed
sortedSet.add( someInt );
// If you need an array at the end
Integer[] array = sortedSet.toArray( new Integer[sortedSet.size()] );