This question is for real brainiacs, cause it should be done without an auxiliary array
and has to be most efficient!
C program - needs to recieve an array with X numbers
(suppose X=4 array : 5,4,3,2)
and check if the array has all the numbers from 0 to X-1
(If X is 44 it needs to check if all numbers between 0 to 43 inside the array).
It has to be super efficient - I mean, running on the array 43 times is not an option!
Do you have any idea how to do this?? I'm trying to figure this one for hours without any success!!
It has to be O(n).
If changing order of the array is allowed you can use in-place sort algorithm, then check if for some i:
array[i] == array[i+1]
Time complexity can be O(n*lg n) then.
You can simplify the problem to finding duplicates.
Proof:
If the length of the array is not X => There are numbers missing. You can easily check that in O(1) or O(n).
Else => you have either all the correct numbers or there are duplicates.
Having that, you can use this implementation: Finding duplicates in O(n) time and O(1) space. Also make sure you check the bounds of the array. If the numbers are not inside the bounds, the array contains incorrect numbers.
This leads to an O(n) solution.
Sort both arrays (is in O(n log n)). Then treat both arrays as queues:
If the head elements of both queues are equal, print one of them and pop both.
If the head elements are not equal, pop the smaller.
Repeat.
You could sort the array, and then scan through it once. That should give you O(N log N) performance, better than the O(N^2) you'd need for the naive approach.
foreach(int i in array)
{
int count = 0;
foreach(int i2 in array)
{
if(i == i2)
{
count++;
}
}
if(count > 1)
{
return false;
}
}
return true;
See some brilliant answers here, a C++ implementation of the #caf's answer could be
bool stop=true;
// first place the element i at location A[i], i.e 4 at A[4]
for(int i = 0; i<n; i++) {
while (A[A[i]] != A[i]){
swap(A[i], A[A[i]])
}
}
// than u can have the second loop which does the decision
for(int i = 0; i<n && !stop; i++) {
if (A[i] != i){
stop = true;
}
}
if (stop)
printf("duplicate");
else
printf("not duplicate)
an O(n) solution: The algorithm tries to put each element in the array onto its correct position, e.g. 1 onto a[0] and 2 onto a[1], by swapping with the element occupies the origin position.
at first, i = 1, a[i - 1] = 1, it's ok and nothing will be touched
i = 1
a = 1 6 3 4 5 7 1
then, i = 2, a[i - 1] = 6 != 2, then swap a[i - 1] and a[6 - 1]
i = 2
a = 1 7 3 4 5 6 1
then, i is still 2, but a[i - 1] == 7 != 2, then swap a[i - 1] and a[7 - 1]
i = 2
a = 1 1 3 4 5 6 7
now i = 2 but we see that a[i - 1] == a[1 - 1], thus we find the duplicate
full source:
#include <stdio.h>
int main() {
int a[7] = {1, 6, 3, 4, 5, 7, 1};
int i, t;
for (i = 0; i < 7; ++i) {
while (a[i] != i + 1) {
if (a[i] == a[a[i] - 1]) {
printf("duplicate: %d\n", a[i]);
goto out;
}
t = a[i];
a[i] = a[a[i] - 1];
a[t - 1] = t;
}
}
printf("no duplicate\n");
out:
return 0;
}
You can use a modified merge operation (like the one used in mergesort) if the arrays are both sorted.
You can do [on average case] better then the suggested O(nlogn) solution.
There is an O(n) armotorized average case solution using hash tables:
hash <- new hash set
for each e in A:
hash.add(e)
for each e in B:
if hash.contains(e): print e
You can overcome printing twice elements if they appear twice in B by storing an additional hash set of 'printed' elements.
If latency or worst case performacne is an issue, use one of the sort and iterate solutions suggested.
Sort the smaller and use binary search to search it for each element in the larger. That way, you can do it in O((n1+n2)*log(n1)) where n1, n2 are the sizes of the arrays (n1 is the smaller).
I don't understand what I'm missing in this question but AFAIK I don't see a reason why any (reasonable) solution should be anything more-/worse- than O(n) time (and space) complexity.
From the above comments and answers, I understand the following:
Negative numbers : I'm not sure whether negative numbers are allowed or not. The OP says check if all the array has all the numbers from 0 to X-1. So anything less than 0 is not expected in the array. So I assume negative numbers are not allowed
Duplicate numbers : referring to the same quote from the OP - check if all the array has all the numbers from 0 to X-1 I guess if X is the size of the array and all numbers from 0 to X-1 should be present, the I guess no duplicate numbers are allowed.
So making the above assumptions, we can use one bit to check whether i (0 <= i <= X-1) is present or not. If i is duplicate then it will fail mentioning that there is a duplicate number.
It scans the whole array one time - O(n) and just uses one bit per element, so X is 10 the X bits are needed - for example consider we need to handle 1000000 elements and sizeof(int) is 4 then we need 3.82M of memory to hold the array elements and only 0.48M is used for storing the presence of an element.
#include <stdio.h>
#define X 10
#define MIN 0
#define MAX X-1
int main(void)
{
//int arr[X] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
//int arr[X] = {6, 7, 8, 9, 0, 5, 3, 2, 11, 12};
//int arr[X] = {1, 1, 2, 4, 5, 6, 7, 8, 2, 2};
int arr[X] = {1, 3, 2, 4, 5, 6, -7, 8, 2, 2};
/* if X is more than sizeof(int) then change
the flag type to a wider one! */
int flag = 0;
int i;
for(i=0 ;i<X ; i++) {
if (arr[i] >= MIN && arr[i] <= MAX) {
if (flag & 1<<arr[i]) {
printf("Duplicate found : %d \n", arr[i]);
return -1;
}
flag |= 1<<arr[i];
} else {
printf("Failure at %d : %d \n", i, arr[i]);
return -1;
}
}
printf("Success \n");
return 0;
}
Read this for an answer - array validation - without using an auxiliary array
an array of n elements which contains elements from 0 to n-1, with any of these numbers appearing any number of times.
For example, let n be 7 and array be {1, 2, 3, 4, 5, 4, 6}, the answer should FALSE
Isn't the above statements contradict themselves?!
Related
I have an array of 32 numbers [1,2,3,4,4,4,4,5,5,5,5,5,6,6,7,7,7,7,8,9,10,10,11,12,13,13,14,14,15,16,17,17]
I want to partition this array into 8 sub arrays each of size 4 such that no sub array has duplicate elements.
In how many ways can I do this? What is most optimal solution to generate all permutations and a single random permutation. Order of sub arrays do not matter. Neither does order of elements inside each sub array.
For my original problem I do not need to generate all permutations. I just have to generate a random permutation every time my program is run.
My approach was to randomly shuffle array using Fisher–Yates algorithm and keep reshuffling it until I get all 8 sub arrays with no duplicate elements. Of course this is not the best approach.
As part of my solution I shuffle array and from this shuffled array start adding elements one by one to sub arrays. If any sub array had a number already then I keep skipping elements from my shuffled array until I reach a number which is not is my sub arrays. This approach fails for some cases.
Pseudocode of what I have tried
let shuffledArray = shuffle(originalArray);
let subArrays = [];
for (let i = 0; i < 8; i++) {
subArrays[i] = [];
for (let j = 0; j < 32; j++) {
if (!subArrays[i].contains(shuffledArray[j]) && !shuffledArray[j].used) {
subArrays[i].push(shuffledArray[j])
shuffledArray[j].used = true;
}
if (subArrays[i].length == 4) {
break;
}
}
}
if subArrays has any sub array such that it has duplicate elements then repeat above steps
else we have generated a random permutation
As you can see above approach fails when after shuffling all duplicate numbers lie at the end so as a hack I repeat all steps again and again till I get result.
I am using JavaScript but answers in any language are welcome as long as they can be converted into JavaScript.
Also it would be great if anyone can provide general solution for N elements and K number of groups.
This is my first question at SO. Feel free to edit/suggest improvements.
An option is to first break up your list into groups of identical numbers, then sort by length. Then you can make groups by taking elements from each group starting at the longest, second-longest, third-longest, fourth-longest. When you empty a subgroup, remove it.
Here's JS implementation:
function partition(arr, N){
// group items together and sort by length
// groups will be [[5, 5, 5, 5, 5], [4, 4, 4, 4], ...]
let groups = Object.values(l.reduce((obj, n) =>{
(obj[n] || (obj[n] = [])).push(n)
return obj
}, {})).sort((a,b) => b.length - a.length)
let res = []
while(groups.length >= N){
let group = []
let i = 0
while (group.length < N){
group.push(groups[i].pop())
if (groups[i].length < 1) groups.splice(i, 1)
else i++
}
res.push(group)
}
return res
}
let l = [1,2,3,4,4,4,4,5,5,5,5,5,6,6,7,7,7,7,8,9,10,10,11,12,13,13,14,14,15,16,17,17]
console.log(partition(l, 4).map(arr => arr.join(',')))
// with 5
console.log(partition(l, 5).map(arr => arr.join(',')))
You can use bitmasking for this problem. Start by generating all 17-bit numbers which have exactly 4 bits set to 1. These numbers will represent the possible elements in one group in a way that if the i'th bit of the number is set, i+1 is part of that group.
Now, out of these generated numbers, your task is just to select 8 numbers repeatedly satisfying the frequency constraints of each element which can be done easily.
I'll get back to you if I find some other approach.
EDIT: Alternatively, you can use recursion in following way: start with 8 numbers, all initially set to 0, start by setting (a[i]-1)'th bit to 1 in exactly one of those numbers which that bit set to 0 and total set bits in that number are less than 4.
When you reach the leaf in recursion, you'll have 8 numbers representing the bitmasks as described above. You can use them for partition.
You can use this approach by creating let's say 100 sets of 8 numbers initially and return from the recursion. Once all these 100 are utilized, you can run this recursion again to create double the sets formed in the previous step and so on.
#include<bits/stdc++.h>
using namespace std;
int num=0;
vector<vector<int> > sets;
void recur(int* arr, vector<int>& masks, int i) {
if(num == 0)
return;
if(i==32){
vector<int> newSet;
for(int j=0; j<8; j++)
newSet.push_back(masks[j]);
sort(newSet.begin(), newSet.end());
int flag=0;
for(int j=0; j<sets.size(); j++){
flag=1;
for(int k=0; k<8; k++)
flag = flag && (newSet[k] == sets[j][k]);
if(flag) break;
}
if(!flag){
sets.push_back(newSet);
num--;
}
return;
}
for(int ii=0; ii<8; ii++) {
if(__builtin_popcount(masks[ii]) < 4 && (masks[ii] & (1 << (arr[i]-1))) == 0){
masks[ii] = masks[ii] ^ (1<<(arr[i] - 1));
recur(arr, masks, i+1);
masks[ii] = masks[ii] ^ (1<<(arr[i] - 1));
}
}
}
int main() {
num = 100;
int num1 = num;
vector<int> masks;
for(int i=0; i<8; i++)
masks.push_back(0);
int arr[] = {1,2,3,15,16,4,4,4,4,5,5,5,5,5,6,6,7,7,7,7,8,9,10,10,11,12,13,13,14,14,17,17};
recur(arr, masks, 0);
for(int j=0; j<num1; j++){
for(int i=0; i<8; i++){
//ith group
printf("%d group : ",i);
for(int k=0; k<17; k++){
if(sets[j][i] & (1<<k))
printf("%d ",k+1);
}
printf("\n");
}
printf("\n\n\n======\n\n\n");
}
return 0;
}
Is this what you are looking for?
Here's a demonstration of enumerating all possibilities of a set (not a multiset as in your example), just to show how rapidly the number of combinations increases. The number of combinations for a partition of 8 4-element parts will be enormous. I'm not sure, but you may be able to adapt some of these ideas to incorporate the multiset or at least first conduct a partial enumeration and then add on the repeated elements randomly.
function f(ns, subs){
if (ns.length != subs.reduce((a,b) => a+b))
throw new Error('Subset cardinality mismatch');
function g(i, _subs){
if (i == ns.length)
return [_subs];
let res = [];
const cardinalities = new Set();
function h(j){
let temp = _subs.map(x => x.slice());
temp[j].push(ns[i]);
res = res.concat(g(i + 1, temp));
}
for (let j=0; j<subs.length; j++){
if (!_subs[j].length && !cardinalities.has(subs[j])){
h(j);
cardinalities.add(subs[j]);
} else if (_subs[j].length && _subs[j].length < subs[j]){
h(j);
}
}
return res;
}
let _subs = [];
subs.map(_ => _subs.push([]));
return g(0, _subs);
}
// https://oeis.org/A025035
let N = 12;
let K = 3;
for (let n=K; n<=N; n+=K){
let a = [];
for (let i=0; i<n; i++)
a.push(i);
let b = [];
for (let i=0; i<n/K; i++)
b.push(K);
console.log(`\n${ JSON.stringify(a) }, ${ JSON.stringify(b) }`);
let result = f(a, b);
console.log(`${ result.length } combinations`);
if (n < 7){
let str = '';
for (let i of result)
str += '\n' + JSON.stringify(i);
console.log(str);
}
console.log('------');
}
The following python code uses a simple method for producing a random partitioning each time it is run. It shuffles the list of 32 integers (to give a random result) then uses a first-fit + backtracking method to find the first arrangement that results from that shuffle. Efficiency: The Fisher-Yates shuffle used here is an O(n) algorithm. Finding the first arrangement from a shuffle can be close to O(n) or can be far worse, depending on the original numbers and on the shuffle, as noted below.
Caveats: Ideally, having a different shuffle should lead to a different partition. But that cannot be, because there are so many more different shuffles than different partitions (perhaps 1020 times as many shuffles vs partitions). Also ideally, every possible partition should have equal probability of being produced. I don't know if that's the case here, and don't even know whether this method covers all possible partitions. For example, it's conceivable that some partitions cannot be generated by a first-fit + backtracking method.
While this method generates the vast majority of its solutions quite quickly -- eg under a millisecond -- it sometimes gets bogged down and wastes a lot of time due to conflicts occurring early in the recursion that aren't detected until several layers deeper. For example, times for finding four sets of 1000 different solutions each were 96 s, 166 s, 125 s, and 307 s, while times for finding sets of 100 different solutions included 56 ms, 78 ms, 1.7 s, 5 s, 50 s.
Some program notes: In the shuffled list s we keep 2mn-k instead of k. Working with the data as bit masks instead of as counting numbers speeds up tests for duplicates. Exponent mn-k (in 2mn-k) lets array u sort so that output is in ascending order. In python, # introduces comments. Brackets with a for expression inside represent a "list comprehension", a way of representing a list that can be generated using a for statement. The expression [0]*nc denotes a list or array of nc elements, initially all 0.
from random import randint
A = [1,2,3,4,4,4,4,5,5,5,5,5,6,6,7,7,7,7,8,
9,10,10,11,12,13,13,14,14,15,16,17,17] # Original number list
ns = len(A) # Number of numbers
nc = 8 # Number of cells
mc = 4 # Max cell occupancy
rc = range(nc) # [0,1,...nc-1]
mn = max(A) # Max number
s = [ 2**(mn-k) for k in A]
for i in range(ns-1,0,-1):
j = randint(0,i)
s[i], s[j] = s[j], s[i] # Do a shuffle exchange
# Create tracking arrays: n for cell count, u for used numbers.
n = [0]*nc
u = [0]*nc
def descend(level):
if level == ns:
return True
v = s[level] # The number we are trying to place
for i in rc:
if (v & u[i] == 0) and n[i] < mc:
u[i] |= v # Put v into cell i
n[i] += 1
if descend(level+1):
return True # Got solution, go up and out
else:
u[i] ^= v # Remove v from cell i
n[i] -= 1
return False # Failed at this level, so backtrack
if descend(0):
for v in sorted(u, reverse=True):
c = [ mn-k for k in range(mn+1) if v & 2**k]
print (sorted(c))
else:
print ('Failed')
Some example output:
[1, 2, 5, 9]
[3, 4, 6, 14]
[4, 5, 6, 10]
[4, 5, 7, 17]
[4, 10, 15, 16]
[5, 7, 8, 17]
[5, 7, 11, 13]
[7, 12, 13, 14]
[1, 4, 7, 13]
[2, 5, 7, 8]
[3, 4, 5, 17]
[4, 5, 6, 14]
[4, 6, 7, 9]
[5, 10, 11, 13]
[5, 10, 12, 16]
[7, 14, 15, 17]
Below is code snippet to reorder odd numbers followed by even numbers without changing the order of even/odd numbers in original array.
input - {1, 4, 8, 3, 9, 12, 7}
output - {1, 3, 9, 7, 4, 8, 12}
Can We improve this from O(n2) in space (without using extra space)?
public static void reOrder(int[] arr) {
int evenIndex = arr.length;
for(int i=0; i < arr.length;i++) {
if(arr[i] % 2 == 0 && evenIndex == arr.length) //even index
evenIndex = i;
else if( arr[i] % 2 != 0 ) {
if(i > evenIndex ) {
shift (arr, evenIndex , i);
evenIndex ++;
}
}
}
}
static void shift(int[] arr, int evenIndex, int endIndex) {
int temp = arr[endIndex];
for(int i = endIndex; i > evenIndex ;i --) {
arr[i] = arr[i-1];
}
arr[evenIndex] = temp;
}
Stable partition is what you are looking for
std::vector<int> l = {1, 4, 8, 3, 9, 12, 7};
std::stable_partition(l.begin(), l.end(),
[](int A) -> bool {
return (A & 1) == 1; // A is odd
});
Exactly N applications of the predicate and O(N) swaps if there is enough extra memory. O(N log N) swaps and O(N) applications of the predicate
Question on how stable partition works along with its complexity.
A stable quick sort, for example, will use a stable partitioning under the hood. Check out the accepted answer here for an O(n*log(n)) implementation of a stable partition algorithm that is beautifully recursive.
You didn't specify any language tag, so I'll answer using python (just because it's quicker for me to use it at the moment).
If you only care about space complexity you can do something like this:
l = [1, 4, 8, 3, 9, 12, 7]
even_index = -1
for index in range(0, len(l)):
if (l[index] % 2) == 0:
if even_index == -1:
even_index = index
else:
if (index > 0) and (even_index > -1):
num = l[index]
l.insert(even_index, num)
del l[index + 1]
even_index += 1
print(l)
You keep an index of where the first even number is and insert the odd number as you find them going through the list. Then you remove the odd number at the "old" index (which is now increased by 1).
I think the space complexity is what you need, but the time complexity can be improved.
For example, in Python a collections.deque is probably better in this case, but time complexity was not a priority.
Let's say you have an array of integers. Find all positions p (if they exists) so that the sum of elements from 0 to p is equal to the sum of elements from p + 1 to the end of the array.
Java is preferred for the answer but any other language is fine, thank you.
If you can assume that all integers are positive, then it simplifies the problem greatly. You can walk through the array once to find the sum, and then walk a second time until you (possibly) find a point where the two sums are equal. The reason this works is that moving either left or right will always increase/decrease the sum. However, there may be zeroes present, and these also need to be considered.
public List<Integer> getPosition(int[] array) {
List<Integer> result = new ArrayList<Integer>();
// first walk through the array to determine the total sum
// cost is O(N)
int sum = 0;
for (int i=0; i < array.length; ++i) {
sum += array[i];
}
// next walk through the array again, checking at each step
// if the running sum be half the total
// cost is O(N)
int runningSum = 0;
int position = -1;
for (int i=0; i < array.length; ++i) {
runningSum += array[i];
// if position found, then break
if (runningSum == sum / 2) {
position = i;
break;
}
}
result.add(position);
// there may be zeroes to the right of the pivot
// if so, they are also valid points and must be added
if (position != -1) {
int i = position + 1;
while (array[i] == 0) {
result.add(i);
++i;
}
}
return result;
}
int[] myArray = new int[] {1, 3, 2, 8, 5, 1, 0, 0, 0, 9, 5, 6};
List<Integer> position = getPosition(myArray);
Output:
[5, 6, 7, 8]
This answer makes sense because 0 - 5 has a sum of 20 and 6 - 11 also has a sum of 20. In addition, we could also start at positions 6, 7, or 8 and also divide the array into two sums of 20.
[1, 3, 2, 8, 5, 1, 0, 0, 0, 9, 5, 6]
^ this value of p divides the array into two sums of 20
^ ^ ^ but any of these values also divide the array
One way to solve this problem is to note that the sum of elements from 0 to p must exactly equal the total sum of all elements divided by 2.
This is because both parts (the 0 to p part and the p+1 to the end part) must be equal and the two parts added together make the entire array.
For this solution, you would simply perform two passes.
In the first pass, you sum up all of the elements in the array.
In the second pass, you are looking for every index such that the sum of the array up to that index equals half of the total sum.
In psuedocode:
total_amount = sum(array)
current_partial_sum = 0
for i in index of array:
current_partial_sum += array[i];
if (current_partial_sum == total_amount/2) {
add i to the solution
}
}
I have two arrays, i have to choose some elements from the first array so that their sum is maximised while the sum of the corresponding elements of second array is less than k.
I can think of a recursive solution till now, i need an iterative solution.
example :
array 1 : 2 2 5 4 3 6 10
array 2 : 4 3 2 5 4 10 7 and k = 15
all the numbers are positive.
Suppose each array has n elements. One solution is to try all possible combinations of the n elements, which means time complexity is O(2^n).
While use dynamic programming can achieve O(n*k) time complexity:
dp[i][j] = x means for the first i elements, select some elements from array 2, and the sum of selected elements of array 2 is j (0 <= j < k), the max sum of corresponding selected elements of array 1 is x. Then we want dp[n][j] (0 <= j < k) maximum.
The state transition equation is to try whether the ith element of array 2 is selected. If not selected, dp[i][j] = dp[i-1][j]; If selected, dp[i][j] can be max(dp[i-1][j], dp[i-1][j-b[i]] + a[i]), here b[i] <= j < k.
for(int i=1;i<=n;i++) {
for(int j=0;j<k;j++) {
dp[i][j] = 0;
}
}
if(b[1] < k) {
dp[1][b[0]] = a[0];
}
for(i=2;i<=n;i++) {
for(j=0;j<k;j++) {
dp[i][j] = dp[i-1][j];
if(j >= b[i] && dp[i-1][j - b[i]] + a[i] > dp[i][j]) {
dp[i][j] = dp[i-1][j - b[i]] + a[i];
}
}
}
The answer is max(d[[n][j]), 0 <= j< k.
Please select different algorithm according to how big n and k are.
Each element of the array can be either present of missing thus resulting in 2^N combinations to be evaluated. You can, for example, generate numbers from 0 to 2^N-1 and use their individual bits as indicators of such presence/absence.
The whole solution can be found by this Python one-liner (split into three lines here):
import itertools
a1 = [2, 2, 5, 4, 3, 6, 10]
a2 = [4, 3, 2, 5, 4, 10, 7]
k = 15
print sorted((sum(itertools.compress(a1, s)), s)
for s in itertools.product([0, 1], repeat=len(a1))
if sum(itertools.compress(a2, s)) < k)[-1][1]
I have a problem to find common elements in two arrays and that's of different size.
Take , Array A1 of size n and Array A2 of size m, and m != n
So far, I've tried to iterate lists one by one and copy elements to another list. If the element already contains mark it, but I know it's not a good solution.
Sort the arrays. Then iterate through them with two pointers, always advancing the one pointing to the smaller value. When they point to equal values, you have a common value. This will be O(n log n+m log m) where n and m are the sizes of the two lists. It's just like a merge in merge sort, but where you only produce output when the values being pointed to are equal.
def common_elements(a, b):
a.sort()
b.sort()
i, j = 0, 0
common = []
while i < len(a) and j < len(b):
if a[i] == b[j]:
common.append(a[i])
i += 1
j += 1
elif a[i] < b[j]:
i += 1
else:
j += 1
return common
print 'Common values:', ', '.join(map(str, common_elements([1, 2, 4, 8], [1, 4, 9])))
outputs
Common values: 1, 4
If the elements aren't comparable, throw the elements from one list into a hashmap and check the elements in the second list against the hashmap.
If you want to make it efficient I would convert the smaller array into a hashset and then iterate the larger array and check whether the current element was contained in the hashset. The hash function is efficient compared to sorting arrays. Sorting arrays is expensive.
Here's my sample code
import java.util.*;
public class CountTest {
public static void main(String... args) {
Integer[] array1 = {9, 4, 6, 2, 10, 10};
Integer[] array2 = {14, 3, 6, 9, 10, 15, 17, 9};
Set hashSet = new HashSet(Arrays.asList(array1));
Set commonElements = new HashSet();
for (int i = 0; i < array2.length; i++) {
if (hashSet.contains(array2[i])) {
commonElements.add(array2[i]);
}
}
System.out.println("Common elements " + commonElements);
}
}
Output:
Common elements [6, 9, 10]
In APL:
∪A1∩A2
example:
A1←9, 4, 6, 2, 10, 10
A1
9 4 6 2 10 10
A2←14, 3, 6, 9, 10, 15, 17, 9
A2
14 3 6 9 10 15 17 9
A1∩A2
9 6 10 10
∪A1∩A2
9 6 10
Throw your A2 array into a HashSet, then iterate through A1; if the current element is in the set, it's a common element. This takes O(m + n) time and O(min(m, n)) space.
Looks like nested loops:
commons = empty
for each element a1 in A1
for each element a2 in A2
if a1 == a2
commons.add(a1)
Schouldn't matter at all if the arrays have the same size.
Depending on the language and framework used, set operations might come in handy.
Try heapifying both arrays followed by a merge to find the intersection.
Java example:
public static <E extends Comparable<E>>List<E> intersection(Collection<E> c1,
Collection<E> c2) {
List<E> result = new ArrayList<E>();
PriorityQueue<E> q1 = new PriorityQueue<E>(c1),
q2 = new PriorityQueue<E>(c2);
while (! (q1.isEmpty() || q2.isEmpty())) {
E e1 = q1.peek(), e2 = q2.peek();
int c = e1.compareTo(e2);
if (c == 0) result.add(e1);
if (c <= 0) q1.remove();
if (c >= 0) q2.remove();
}
return result;
}
See this question for more examples of merging.
The Complexity of what I give is O(N*M + N).
Also note that it is Pseudocode C And that it provides distinct values.
eg.[1,1,1,2,2,4] and [1,1,1,2,2,2,5] Will return [1,2]
The Complexity is
N*M cause of the for loops
+ N cause of the checking if it already exists in the ArrayCommon[] (which is n size in case Array2[] contains data which duplicate Part of the Array1[] Assuming N is the size of the smaller Array (N < M).
int Array1[m] = { Whatever };
int Array2[n] = { Whatever };
int ArrayCommon[n] = { };
void AddToCommon(int data)
{
//How many commons we got so far?
static int pos = 0;
bool found = false;
for(int i = 0 ; i <= pos ; i++)
{
//Already found it?
if(ArrayCommon[i] == data)
{
found = true;
}
}
if(!found)
{
//Add it
ArrayCommon[pos] = data;
pos++;
}
}
for(int i = 0 ; i < m ; i++)
{
for(int j = 0 ; j < n ; j++)
{
//Found a Common Element!
if(Array1[i] == Array2[j])
AddToCommon(Array1[i]);
}
}
In Python, you would write set(A1).intersection(A2). This is the optimal O(n + m).
There's ambiguity in your question though. What's the result of A1=[0, 0], A2=[0, 0, 0]? There's reasonable interpretations of your question that give 1, 2, 3, or 6 results in the final array - which does your situation require?
I solve the problem by using Set intersection. It is very elegant. Even though I did not analyze the time complexity, it is probably in reasonable range.
public Set FindCommonElements(Integer[] first, Integer[] second)
{
Set<Integer> set1=new HashSet<Integer>(Arrays.asList(first));
Set<Integer> set2=new HashSet<Integer>(Arrays.asList(second));
// finds intersecting elements in two sets
set1.retainAll(set2);
return set1;
}
class SortedArr
def findCommon(a,b)
j =0
i =0
l1=a.length
l2=b.length
if(l1 > l2)
len=l1
else
len=l2
end
while i < len
if a[i].to_i > b[j].to_i
j +=1
elsif a[i].to_i < b[j].to_i
i +=1
else
puts a[i] # OR store it in other ds
i +=1
j +=1
end
end
end
end
t = SortedArr.new
t.findCommon([1,2,3,4,6,9,11,15],[1,2,3,4,5,12,15])