Array contains element in Java - java

I've got a task of writing a function that returns integers which are in both two arrays.
For example: nums1 [1,2,3] and nums2 [2,3,5] and answer should be [2,3].
I came with this solution:
public static void main(String[] args) {
System.out.println(arraysIntersection(new int[] {1,2,3}, new int[] {2,3,5}));
}
public static List<Integer> arraysIntersection(int[] nums1, int[] nums2) {
List<Integer> answer = new ArrayList<>();
for (int i = 0; i < nums1.length; i++) {
if (Arrays.asList(nums2).contains(nums1[i])) {
answer.add(nums1[i]);
}
}
return answer;
}
however it seems this condition doesn't work as intended:
if (Arrays.asList(nums2).contains(nums1[i]))
It says it doesn't contain the value altough it clearly contains 2 and 3. Any ideas?
I know I could just iterate each i over the second array but I thought this solution would be faster. Does anyone knows why it's not working?

You can do it in O(NlogN) time complexity and O(n) memory. Just sort arrays and use two pointers technique.
List<Integer> answer = new ArrayList<>();
int j = 0;
Arrays.sort(nums1);
Arrays.sort(nums2);
for(int i = 0; i < nums1.length; i++) {
if(i > 0 && nums1[i] == nums1[i - 1]) //we have already processed this number
continue;
while(j < nums2.length && nums2[j] < nums1[i])
j++;
if(j < nums2.length && nums1[i] == nums2[j])
answer.add(nums1[i]);
}
return answer;
You can do it in O(N) time complexity and O(n) memory (but constant is higher). Just add all elements of nums1 in first HashSet and all elements of nums2 if another HashSet. Then you can for each element in first set check if another set contains this element using O(1)* time.
List<Integer> answer = new ArrayList<>();
Set<Integer> set1 = new HashSet<>(), set2 = new HashSet<>();
set1.addAll(nums1);
set2.addAll(nums2);
for(var el : set1) {
if(set2.contains(el)) {
answer.add(el);
}
}
return answer;
*O(1) is middle time of operations with hashset

If Arrays is a static object already initialized, or declared at global scope, it may be OK, I don't know for sure. Can't call asList() on an uninitialized object, it must be allocated first.
Now I know, Arrays is a member of the utils package, can be OK.
But not anything that looks fine in code, actually works also.
As a matter of fact, I don't like the way in which Java calls a function. But it would be more easier and handy like this.
I don't know, if you had included the util package in your code.
util, or utils ? Can be 2 different packages, this is important.
You can try another way:
import java.util.*;
public static List<Integer> arraysIntersection(int[] nums1, int[] nums2){
List<Integer> answer = new ArrayList<>();
for (int i = 0; i < nums1.length; i++) {
int u = nums1[i];
for (int j = 0; j < nums2.length; j++) {
if (u == nums2[j]) {
answer.add(u);
break;
}
}
}
return answer;
}
A break could be necessary, if the values must be added only once.
( a number can be found more times into an array )
The break was meant just for ending the inner loop.
The outer loop should continue up to the end of the search.
But the same number can be find more times in the first array.
Before returning the answer, the result should be checked for duplicate values. And this is another problem.
It would be more convenient to check before adding number to list.
Check if the answer list already contains the number value.
And then add the number to the list, if a match is not found.
So this can be done more easier:
if (!answer.contains(u)) answer.add(u);
Since you check this condition, the break is not anymore needed.
But searching the list so many times, can slow down your code.
From this reason, the u value is read only once, before starting to compare with the another array. So you don't have to read manytimes the same array item, just store it in a temporary variable, u.
In another point of view, when iterating over a collection object,
the current value for the current position index could change.
It also depends on the basic interface implementation for this object.
If this function would have been written in C, it would have been a very serious problem, to get the value of an item in array, because the current position of the pointer changes. And here is the same, the current read value changes, excepting that we can't see all the underlying mechanism. And if I am not wrong too much, the original Java first time was based also on the C code.
Best regards, Adrian Brinas.
Have a nice day.

Related

Printing every possible sub-list of a list using recursion

I am having trouble solving this recursion problem. Recursion is quite difficult to understand and be able to code as I am new to coding. The problem is to write a recursive method to find every possible sub-list of a given list. Your method should accept a list of strings as a parameter and print every sub-list that could be created from elements of that list, one per line. Assume there is no duplicates and the list is not null. Do not use any loops.
The only possible way I can think of doing this is with a for loop or use more parameters but I can't per instructions. This is what I have so far. I checked the list api it says there is a subList method you can use. I was able to print the first 5 possible sublists just by substracting -1 from the list size every recursion and then I get an index error. This is very frustrating so if anyone has any tips or pointers that would greatly be appreciated.
If you can possibly solve it with loops, I'd love to see how you would solve it.
public static void main(String[]args){
ArrayList<String> list = new ArrayList<>(List.of("Janet", "Robert", "Morgan", "Char"));
subsets(list);
}
public static void subsets(List<String> list) {
int n = list.size();
if(list.isEmpty()){
System.out.println(list);
}
if(n > 0){
System.out.println(list.subList(0 , n));
}
subsets(list.subList(0,n -1));
}
Results of my code
The best solution I came up with is based on randomness, I'll post in even though it is not what is expected by the Java Programming textbook.
You can calculate how many distinct k-combinations of K elements exists in a list of N elements.
For example:
One combination of 4 elements exists in a list of 4
4 combinations of 3 elements exist in a list of 4.
The idea is to have as args of the recursive method:
The initial list you want to extract sublists
A list of every sublist already printed
The number K of elements of the wanted sublist size
You should then have the following method signature:
public static void subsets(List<String> list, ArrayList<List<String>> alreadyPrinted, int nbOfElementsInTheSubList);
and the call in your main method will be
subsets(list, new ArrayList<>(), list.size());
Now in the body of the recursive method, process as follow (pseudo-code)
Pick a sublist of nbOfElementsInTheSubList random elements from list that is not in alreadyPrinted, print it, and add it to alreadyPrinted
compute combinationNumber = list.size() choose nbOfElementsInTheSubList (ie: the number of nbOfElementsInTheSubList-combination in list)
compare it to alreadyThere, the number of combination of nbOfElementsInTheSubList elements presents in alreadyPrinted
if alreadyThere = combinationNumber : You have all the nbOfElementsInTheSubList-Combination available in list, you can call recursively your method using (nbOfElementsInTheSubList - 1) as the last arg
else : You are missing at least one of the nbOfElementsInTheSubList-Combination available in list. Call subset again using the same nbOfElementsInTheSubList but with the updated alreadyPrinted
I doubt this is an optimal solution, so I bookmarked your topic since I am sincerely curious about the expected code.
If we want to permutate all the value in the list then we can use this code->
public static void main(String[] args) {
List<String> list = Arrays.asList("Janet", "Robert", "Morgan", "Char");
recursiveprint(list, new boolean[list.size()], "");
}
private static void recursiveprint(List<String> list, boolean b[], String s) {
System.out.println(s);
for (int j = 0; j < list.size(); j++) {
if (b[j] == false) {
b[j] = true;
recursiveprint(list, b, s + list.get(j)+" ");
b[j] = false;
}
}
}

Optimal way to check for common element among many lists?

I understand that ArrayList<>'s are fastest for searching (O(1) vs. O(n)) and LinkedList<>'s are fastest for inserting & deleting (O(1) vs. O(n)).
My question is, if using a combination of these two, what is the optimal method to check many lists (>2) for common elements?
Current Method
Using three lists and an iterative method:
out:
for(int a = 0; a < list1.size(); a++) {
for(int b = 0; b < list2.size(); b++) {
for(int c = 0; c < list3.size(); c++) {
if(list1.get(a) == list2.get(b) && list1.get(a) == list3.get(c) ) {
System.out.println(list1.get(a)); // list2.get(b) or list3.get(c) could have been subbed
break out;
}
}
}
}
How can this be optimised for efficiency?
EDIT
Thanks for the many helpful responses :)
What I found to work the best was to use the List .retainAll() function.
Again, to find the common elements among three lists, I have refined the method below.
list1.retainAll(list2);
list1.retainAll(list3);
for(int i : list1) {
System.out.println(i);
}
You can get a expected time linear in the number of elements in all lists, assuming the elements implement hashCode:
public static <T> Set<T> commonElements(List<? extends T> list1, List<? extends T>... lists) {
// use LinkedList for efficient delete operation
// make sure elements are distinct to not check the same element multiple times
List<T> commonElements = new LinkedList<>(new HashSet<>(list1));
for (List<? extends T> l : lists) {
// use HashSet for fast contains check
// keep only elements in the list
commonElements.retainAll(new HashSet<>(l));
}
return new HashSet<>(commonElements);
}
This is faster than your approach, since HashSet allows lookup in O(1) expected time.
Note though that for small input lists the preformance can be much worse with this approach.
If you are looking for performance, it would be better to write an API that uses hash look up. list.retainAll(), though is a single clean api call, internally it does lot of processing especially if the argument passed is also a list. Take a look at the implementation of retainAll() of array list here -
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.retainAll%28java.util.Collection%29
You can look at the implementation of the list that you are using and see if that is okay with your performance requirement. If not, you may try something like this...Write an api to return common elements.
private static Set getCommonElements (List dataList, Set dataSet) {
Set commonDataSet = new LinkedHashSet();
if (dataSet == null || dataSet.isEmpty())
return commonDataSet;
for (Object elem: dataList) {
if (dataSet.contains(elem)) {//Hash based look up. Will be faster.
commonDataSet.add(elem);
}
}
return commonDataSet;
}
Then call that repeatedly as below
Set resultSet= new LinkedHashSet(list1);
resultSet= getCommonElements(list2, resultSet);
resultSet= getCommonElements(list3, resultSet);
If you are not concerned about the order, you can just use a hashset instead of linkedhashset.
One problem with this is, this is iterating over the elements in list which will be higher than the common elements. It would be much better if we can iterate over the common elements and look up in the list. But for that, u may have to keep the data in the lists in a hash-baked list/set or maintain a sorted list. Else the lookup will be costly.
You can optimise it using HashMap in java.
Suppose you have n lists with m elements each
Algorithm :
make hashmap h;
loop i=0 to m
loop j=0 to n
increment j[i] key in hashmap h
loop end
loop end
loop i=0 to m for any list
check hashmap value for the element, if equals to n
print element
complexity o(nm),if n <<< m then, complexity(n)
Using the retainAll(List<>) function instead of iterating over each element has significantly reduced run time and improved readability.
New
list1.retainAll(list2);
list1.retainAll(list3);
Old
out:
for(int a = 0; a < list1.size(); a++) {
for(int b = 0; b < list2.size(); b++) {
for(int c = 0; c < list3.size(); c++) {
if(list1.get(a) == list2.get(b) && list1.get(a) == list3.get(c) ) {
System.out.println(list1.get(a));
break out;
}
}
}
}

Remove an object from an ArrayList without (implicitly) looping through it

I am looping through a list A to find X. Then, if X has been found, it is stored into list B. After this, I want to delete X from list A. As speed is an important issue for my application, I want to delete X from A without looping through A. This should be possible as I already know the location of X in A (I found its position in the first line). How can I do this?
for(int i = 0; i<n; i++) {
Object X = methodToGetObjectXFromA();
B.add(X);
A.remove(X); // But this part is time consuming, as I unnecessarily loop through A
}
Thanks!
Instead of returning the object from yhe method, you can return its index and then remove by index:
int idx = methodToGetObjectIndexFromA();
Object X = A.remove(idx); // But this part is time consuming, as I unnecessarily loop through A
B.add(X);
However, note that the remove method may be still slow due to potential move of the array elements.
You can use an iterator, and if performance is an issue is better you use a LinkedList for the list you want to remove from:
public static void main(String[] args) {
List<Integer> aList = new LinkedList<>();
List<Integer> bList = new ArrayList<>();
aList.add(1);
aList.add(2);
aList.add(3);
int value;
Iterator<Integer> iter = aList.iterator();
while (iter.hasNext()) {
value = iter.next().intValue();
if (value == 3) {
bList.add(value);
iter.remove();
}
}
System.out.println(aList.toString()); //[1, 2]
System.out.println(bList.toString()); //[3]
}
If you stored all the objects to remove in a second collection, you may use ArrayList#removeAll(Collection)
Removes from this list all of its elements that are contained in the
specified collection.
Parameters:
c collection containing elements to be removed from this list
In this case, just do
A.removeAll(B);
When exiting your loop.
Addition
It calls ArrayList#batchRemove which will use a loop to remove the objects but you do not have to do it yourself.

Why should we copy an ArrayList in some recursive alogrithms?

http://oj.leetcode.com/problems/subsets-ii/
Given a collection of integers that might contain duplicates, S, return all possible subsets.
Note:
* Elements in a subset must be in non-descending order.
* The solution set must not contain duplicate subsets.
For example,
If S = [1,2,2], a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
The answer is:
public class Solution {
public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] num) {
ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> tmp = new ArrayList<Integer>();
Arrays.sort(num);
sub(num, 0, tmp, ans);
return ans;
}
public void sub(int[] num, int k, ArrayList<Integer> tmp, ArrayList<ArrayList<Integer>> ans) {
ArrayList<Integer> arr = new ArrayList<Integer>(tmp);
ans.add(arr);
for (int i = k; i < num.length; i++) {
if (i != k && num[i] == num[i-1]) continue;
tmp.add(num[i]);
sub(num, i+1, tmp, ans);
tmp.remove(tmp.size()-1);
}
}
}
I don't know why
ArrayList<Integer> arr = new ArrayList<Integer>(tmp);
ans.add(arr);
But not directly:
ans.add(tmp);
If you just want to print out the results, since you remove any element you added after the recursive call, tmp should look exactly the same at both the start and the end of the function, so it shouldn't make any difference (your way would be preferred as it doesn't copy the ArrayList at each step).
But the problem comes in when you add the results to ans.
If you use your way, there would only be a single ArrayList floating around - you'd just be adding it to ans multiple times.
Note that adding it to ans doesn't actually create a copy of it, it just adds a reference to the ArrayList to ans. So changing the original after it's been added also changes that element of ans.
Live demo showing the correct result by printing them out and the incorrect results in the returned array.
Directly adding it will make arr contain/be the same ArrayList instance as tmp. Down in your loop, when you are altering tmp, you would also be altering arr, which isn't your desired procedure.
Reason for not using
ans.add(tmp);
Since tmp is a method argument, so java passes a reference to the ArrayList by value.
So tmp actually a reference to a List, not a List.
So you need to create an ArrayList object with and add that object to ans
ArrayList<Integer> arr = new ArrayList<Integer>(tmp);
ans.add(arr);
If you use ans.add(tmp), then the arrayList which tmp points to will be added to ans, and if any modifications are made later in the code to tmp, then the contents of the element which you added to ans will also change, since both will point to same memory block.

java array exact length

I set an array of integer like below
int[] a = new int[11111];
//if I set
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
I want a method such that it gives me
4 but 11111.
Is there any method which I can use?
You should look into using an ArrayList
ArrayList<Integer> myList=new ArrayList<Integer>();
myList.add(1);
myList.add(2);
myList.add(3);
System.out.println("Size:"+myList.size());
Well, the following method will do what you asked for:
public int m() {
return 4;
}
On the assumption that you want a method that takes an array, and returns the greatest index that has been populated - you're right that the a.length only tells you the size of the array, i.e. the number of cells allocated.
This is going to be harder than you might expect, especially with an int array. Those unassigned cells are initialised to a value of 0. If you might actually use zero values in your array, then there is absolutely no way to tell whether the value in a cell is the "default" zero or one that you've set yourself.
If the array can't have zero values in it, then you'd need to loop over its entire length, checking for the highest index with a corresponding non-zero value; something like this:
public int dynamicLength(int[] a) {
int max = -1;
for (i = 0; i < a.length; i++) {
if (a[i] != 0) max = i;
}
return max;
}
Even then this might not be ideal, since arrays can be sparsely populated. Do you want the count of assigned indices, or the index of the highest assigned index?
The short answer is almost certainly "use an ArrayList".
When you do
int[] a = new int[11111]
It creates an array with 11111 elements and as it is int it will assign it to default value that is 0 so you have array with all values set.
You should move to List
You should use an ArrayList if the size of the array is changing. There is little performance difference.
See here for how to use one. See here for the API also.
I understand that you only want the assigned elements to be counted but it would be safer at runtime and simpler to use an ArrayList. The ArrayList class just wraps a Java array and handles the changing size for you. You can get the size by calling the size() method on the ArrayList.
See this example using a for-each loop if you want to iterate over the elements:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1); //size is 1
list.add(2); //size is 2
list.add(3); //size is 3
list.add(4); //size is 4
for(Integer n : list)
System.out.println(n);
An ArrayList uses an iterator and the for-each loop uses it to iterate over the ArrayList. Makes life much simpler.
As suggested above, using a List is probably the right answer. However, in the interest of solving the original problem, you could try this instead:
Integer[] foo = new Integer[11111];
foo[0] = new Integer(1);
foo[1] = new Integer(2);
foo[2] = new Integer(3);
foo[3] = new Integer(4);
and create a method that counts non-null values:
public static int countItems(Integer[] array) {
int count = 0;
for (Integer i : array) {
if (i != null) {
count++;
}
}
return count;
}
Of course, this will be a pain to manage as you would need to nullify any items no longer needed. It also raises the question of whether you would accept "holes" in your array, e.g. null values amongst non-null values. My example counting function above would accept such holes.
So, yes. Use a List.
You can create a method which calculates the non-0 elements of the array using a for/while loop.

Categories