How to compare two arrays of integers order-insensitively - java

I want Java code that can compare in this way (for example):
<1 2 3 4> = <3 1 2 4>
<1 2 3 4> != <3 4 1 1>
I can't use hashmap table or anything; just pure code without library.
I know there are two ways.
sort them and compare the array index by index
use two for loops and compare the outer index with the inner index. I have been trying with this but still not working:
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(a[i] != a[j] && j == n)
return false;
}
}
return true;
anything wrong with the code ? thanks

Sort & compare. You can't get the complexity better than that, and any "improvement" that you do on the speed comes at the risk that your code will be wrong.
[edit] Actually.... if you know your numbers are relatively small (e.g. say: the arrays only contain numbers between 0 and 1000), that there's an alternative in O(n). Something like this (sorry if the syntax is wrong, I didn't use java lately):
int count[1001]; // already intialized to 0
for(int i=0;i<n;i++){ count[a[i]]++; count[b[i]]--;}
bool arrays_identical = true;
for(int i=0;i<=1000 && arrays_identical; i++)
arrays_identical &= count[i]==0;
Disclaimer: this code doesn't contain "sanity checks" (i.e. the arrays are really of length "n", the numbers are in the prescribed interval) - it's only to illustrate the principle.

Arrays.sort(a);
Arrays.sort(b);
return Arrays.equals(a, b);

Since this is homework, I'm going to guess that a simple quadratic solution (which your original attempt is), is fine. In that case, you can do something like this:
int count(int[] nums, int x) {
int count = 0;
for (int num : nums) {
if (num == x) count++;
}
return count;
}
boolean equals(int[] arr1, int[] arr2) {
if (arr1.length != arr2.length) return false;
for (int x : arr1) {
if (count(arr1, x) != count(arr2, x)) return false;
}
return true;
}
This sacrifices speed for clarity: it's obviously correct!!
Tips
Use for-each whenever applicable; it always read to better readability
Helper functions improve both readability and reusability!

Before you actually start a more computationally complex solution, you can run a fast O(n) test to see if the arrays are the same. There are times when this this will result in a false positive, and you can use more computationally intensive means to investigate further. If it returns false, you can be assured that the arrays are different.
The basic approach is to do a cummulative XOR between the ith elements of the two arrays. If the resulting XOR is non-zero then you know that the two arrays are different. If the XOR is zero, they might be the same, but more work is needed to confirm.
int c_xor = 0; // XOR accumulator
for (int i = 0; i < n; ++i)
c_xor ^= arr1[i] ^ arr2[i];
// They're different if c_xor != 0; the might be the same if c_xor == 0
return c_xor == 0;

I think it would be sensible to check that the lengths of both arrays are equal before doing any iterating. It's a cheap way to opt out of hard work early, and it fixes the following type of failure for the second approach you mention:
{1, 2, 3} seen as equal to {4, 3, 2, 1}

This is a O(n^2) problem. No other solution is faster than comparing the two arrays directly.
The Virgil's solution is cool, except for the fact that it is not really O(n) performance. It is really O(n+1000) performance. The array comparison second time to set the boolean variable is costly and backfires in small arrays.
The solution you wrote is the best except for a bugs.
Here is the error corrected version.
boolean[] matchedPositions = new boolean[n];
for(int k = 0; k < n; k++
{
matchedPositions[k] = false;
}
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(matchedPositions[j] == false && a[i] == a[j])
{
matchedPositions[j] = true;
break;
}
if(j == n - 1)
{
return false;
}
}
}
return true;
In this case if in case the integer matches then the inner loop will break and set or flag the matched position. This is required for arrays with duplicate entries, this will avoid two entries in left array matching with one entry in the right array.
If in case the match did not happen, which is identified by j == n - 1, you will return false.
Since we are expecting a default value of false in boolean its better to flag initialize it.
In reality, this solution has O(n log n + n) performance penalty. Sort and compare has a performance penalty of O(n^2 + n) too. Sort has O(n^2) performance and one loop for checking. But sorting changes the contents of the array and this does not.

if you take one array as 1,2,3,4,3,1,2,4 then the solution is in this way.
2n = total number of integers : 8
//program
int i, j, n = 4;
for(i = 0; i < n; i++)
for(j = n; j < 2n; j++)
{
if( a[i] != a[j])
{
j++;
}
else
{
i++; exit();
}
}
if (i == n)
{ //They both are equal;
}
else if(i != n)
{
//They both are not equal;
}
If it is not working please comment on it.
Thank You.

Here is a fix for the code that you posted.
for(int i = 0; i < n; i++)
{
int j;
for(j = 0; j < n; j++)
{
if(a[i] == b[j]) break;
}
if (j == n) return false;
}
return true;
That algorithm is going to break done for arrays that contain duplicates, however. For example, the array {1, 1, 2, 3} will be found as a match to the array {1, 2, 2, 3}.
I would highly recommend that you implement a sort-and-compare algorithm instead.

Related

Find the first duplicate with the minimal next occurrence

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

CodeFights - issues with time limit when writing FirstDuplicate method

I'm trying to solve the problem below from CodeFights. I left my answer in Java after the question. The code works for all the problems, except the last one. Time limit exception is reported. What could I do to make it run below 3000ms (CodeFights requirement)?
Note: Write a solution with O(n) time complexity and O(1) additional space complexity, since this is what you would be asked to do during a real interview.
Given an array a that contains only numbers in the range from 1 to a.length, find the first duplicate number for which the second occurrence has the minimal index. In other words, if there are more than 1 duplicated numbers, return the number for which the second occurrence has a smaller index than the second occurrence of the other number does. If there are no such elements, return -1.
Example
For a = [2, 3, 3, 1, 5, 2], the output should be
firstDuplicate(a) = 3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3 has a smaller index than than second occurrence of 2 does, so the answer is 3.
For a = [2, 4, 3, 5, 1], the output should be
firstDuplicate(a) = -1.
Input/Output
[time limit] 3000ms (java)
[input] array.integer a
Guaranteed constraints:
1 ≤ a.length ≤ 105,
1 ≤ a[i] ≤ a.length.
[output] integer
The element in a that occurs in the array more than once and has the minimal index for its second occurrence. If there are no such elements, return -1.
int storedLeastValue = -1;
int indexDistances = Integer.MAX_VALUE;
int indexPosition = Integer.MAX_VALUE;
for (int i = 0; i < a.length; i++)
{
int tempValue = a[i];
for (int j = i+1; j < a.length; j++) {
if(tempValue == a[j])
{
if(Math.abs(i-j) < indexDistances &&
j < indexPosition)
{
storedLeastValue = tempValue;
indexDistances = Math.abs(i-j);
indexPosition = j;
break;
}
}
}
}
return storedLeastValue;
Your solution has two nested for loops which implies O(n^2) while the question explicitly asks for O(n). Since you also have a space restriction you can't use an additional Set (which can provide a simple solution as well).
This question is good for people that have strong algorithms/graph theory background. The solution is sophisticated and includes finding an entry point for a cycle in a directed graph. If you're not familiar with these terms I'd recommend that you'll leave it and move to other questions.
Check this one, it's also O(n) , but without additional array.
int firstDuplicate(int[] a) {
if (a.length <= 1) return -1;
for (int i = 0; i < a.length; i++) {
int pos = Math.abs(a[i]) - 1;
if (a[pos] < 0) return pos + 1;
else a[pos] = -a[pos];
}
return -1;
}
The accepted answer does not work with the task.
It would work if the input array would indeed contain no bigger value than its length.
But it does, eg.: [5,5].
So, we have to define which number is the biggest.
int firstDuplicate(int[] a) {
int size = 0;
for(int i = 0; i < a.length; i++) {
if(a[i] > size) {
size = a[i];
}
}
int[] t = new int[size+1];
for(int i = 0; i < a.length; i++) {
if(t[a[i]] == 0) {
t[a[i]]++;
} else {
return a[i];
}
}
return -1;
}
What about this:
public static void main(String args[]) {
int [] a = new int[] {2, 3, 3, 1, 5, 2};
// Each element of cntarray will hold the number of occurrences of each potential number in the input (cntarray[n] = occurrences of n)
// Default initialization to zero's
int [] cntarray = new int[a.length + 1]; // need +1 in order to prevent index out of bounds errors, cntarray[0] is just an empty element
int min = -1;
for (int i=0;i < a.length ;i++) {
if (cntarray[a[i]] == 0) {
cntarray[a[i]]++;
} else {
min = a[i];
// no need to go further
break;
}
}
System.out.println(min);
}
You can store array values in hashSet. Check if value is already present in hashSet if not present then add it in hashSet else that will be your answer. Below is code which passes all test cases:-
int firstDuplicate(int[] a) {
HashSet<Integer> hashSet = new HashSet<>();
for(int i=0; i<a.length;i++){
if (! hashSet.contains(a[i])) {
hashSet.add(a[i]);
} else {
return a[i];
}
}
return -1;
}
My simple solution with a HashMap
int solution(int[] a) {
HashMap<Integer, Integer> countMap = new HashMap<Integer, Integer>();
int min = -1;
for (int i=0; i < a.length; i++) {
if (!(countMap.containsKey(a[i]))) {
countMap.put(a[i],1);
}
else {
return a[i];
}
}
return min;
}
Solution is very simple:
Create a hashset
keep iterating over the array
if element is already not in the set, add it.
else element will be in the set, then it mean this is minimal index of first/second the duplicate
int solution(int[] a) {
HashSet<Integer> set = new HashSet<>();
for(int i=0; i<a.length; i++){
if(set.contains(a[i])){
// as soon as minimal index duplicate found where first one was already in the set, return it
return a[i];
}
set.add(a[i]);
}
return -1;
}
A good answer for this exercise can be found here - https://forum.thecoders.org/t/an-interesting-coding-problem-in-codefights/163 - Everything is done in-place, and it has O(1) solution.

Finding all possible subset sum which is equal to 0 out of set of positive and negative numbers? [duplicate]

This question already has answers here:
given a set of n integers, return all subsets of k elements that sum to 0
(3 answers)
Closed 6 years ago.
You have an array which has a set of positive and negative numbers, print all the subset sum which is equal to 0.
I can think of approach where i can cam make all powersets of givcen array and check if their sum is 0. BUt that does not llok like optimized solution to
me.
After reading looks a bit similar problem on net , looks like it can be solved with dynamic programming like below program to find if there is combination exist
to make sum 11 just an example ?
public boolean subsetSum(int input[], int total) {
boolean T[][] = new boolean[input.length + 1][total + 1];
for (int i = 0; i <= input.length; i++) {
T[i][0] = true;
}
for (int i = 1; i <= input.length; i++) {
for (int j = 1; j <= total; j++) {
if (j - input[i - 1] >= 0) {
T[i][j] = T[i - 1][j] || T[i - 1][j - input[i - 1]];
} else {
T[i][j] = T[i-1][j];
}
}
}
return T[input.length][total];
}
public static void main(String args[]) {
TestDynamic ss = new TestDynamic();
int arr1[] = {2, 3, 7, 8};
System.out.print(ss.subsetSum(arr1, 11));
}
But i am not sure how to extend above programe to
1) Include negative number
2) find combination of elements whick makes sum as zero( Above program just finds whether its possible to make given sum but does not
find which set of numbers makes it zero)
Here is a full implementation in Javascript. You can run it with node.js.
function target_sum(a, k, x)
{
if (k == a.length) return [];
if (a[k] == x) {
return [[a[k]]];
} else {
var s = target_sum(a, k + 1, x); // not using a[k]
var t = target_sum(a, k + 1, x - a[k]); // using a[k]
for (var i = 0; i < t.length; ++i) {
t[i].unshift(a[k]); // a[k] is part of the solution
s.push(t[i]); // merge t[] into s[]
}
return s;
}
}
var s = target_sum([1,4,5,2,7,8,-3,-5,-6,9,3,-7,-1,5,6], 0, 0);
for (var i = 0; i < s.length; ++i)
console.log(s[i].join(","));
Note that this is an exponential algorithm. Don't use it on large arrays.
Erwin Rooijakkers also pointed to the right direction. In particular, this post gives another algorithm. I could be wrong about the following – I believe that algorithm trades speed for space. It avoids staging arrays into the call stack, but it has to do more recursions to achieve that.
EDIT: about the algorithm you mentioned. It is not exponential, but it only works for positive numbers if I am right. Its time complexity is also proportional to the target sum, which may not be ideal depending on input.

How to check if every element in an array is lower than another array in Java?

Right now I have the following idea:
int WORK[] = new int[]{5, 4, 3};
int release[] = new int[]{3, 2, 3};
boolean check = false;
for (int i = 0; i < WORK.length; i++)
{
if (WORK[i] >= release[i])
{
for (int j = 0; j < WORK.length; j++)
{
if (WORK[j] >= release[j])
{
for (int k = 0; k < WORK.length; k++)
{
if (WORK[k] >= release[k])
{
check = true;
System.out.print("All elements in work are bigger than release");
break;
}
}
break;
}
}
break;
}
}
if(!check)
{
System.out.print("Not every element in work is bigger than release");
}
Now I want to know if there is a more efficient way to do this? But my main problem is that I need to do this with n elements. With `n´ elements it is not efficient neither useful, because I don't know how many elements will be there.
What I want to know is there a function in Java Arrays or something, which could help me?
Any help?
With Java 8, you can do this in a functional style with streams (this would not be a performance optimization; it's just less code to write).
IntPredicate lowerThanRelease = i -> IntStream.of(release).allMatch(j -> i <= j);
boolean allLower = IntStream.of(work).allMatch(lowerThanRelease);
One efficient way to do this is two have 4 variables
workmax, workmin, needmax, needmin.
Iterate through both arrays one at a time and find the max and min values within that array. Then all you need to do is compare the min value of one array with max value of the second array
This way you just need two loops (no nesting).
Then its a matter of simple comparison.
e.g.
if (workmin > needmax) then System.out.print("All elements in " + work + "are bigger than need");
I think you can come up with the code if you understand the approach mentioned above.
I hope I got your question correctly.
if (array1.length == array2.length) {
for (int i = 0; i < array1.length; i++) {
for (int j =0; j < array2.length; j++) {
// compare array1[i] with array2[j];
}
}
} else {
System.out.println("Arrays have different lengths.");
}
This gives you the opportunity to compare all numbers of one array with all numbers of the second. So your basic idea was not that bad.
Hope it helps.
This one seems very basic, but it should do it.

How would you find how many times one array is repeated in another one?

For example, if you were given {1,2} as the small array and {1,2,3,4,1,2,1,3} as the big one, then it would return 2.
This is probably horribly incorrect:
public static int timesOccur(int[] small, int big[]) {
int sum= 0;
for (int i=0; i<small.length; i++){
int currentSum = 0;
for (int j=0; j<big.length; j++){
if (small[i] == big[j]){
currentSum ++;
}
sum= currentSum ;
}
}
return sum;
}
As #AndyTurner mentioned, your task can be reduced to the set of well-known string matching algorithms.
As I can understand you want solution faster than O(n * m).
There are two main approaches. First involves preprocessing text (long array), second involves preprocessing search pattern (small array).
Preprocessing text. By this I mean creating suffix array or LCP from your longer array. Having this data structure constructed you can perform a binary search to find your your substring. The most efficient time you can achieve is O(n) to build LCP and O(m + log n) to perform the search. So overall time is O(n + m).
Preprocessing pattern. This means construction DFA from the pattern. Having DFA constructed it takes one traversal of the string (long array) to find all occurrences of substring (linear time). The hardest part here is to construct the DFA. Knuth-Morris-Pratt does this in O(m) time, so overall algorithm running time will be O(m + n). Actually KMP algorithm is most probably the best available solution for this task in terms of efficiency and implementation complexity. Check #JuanLopes's answer for concrete implementation.
Also you can consider optimized bruteforce, for example Boyer-Moore, it is good for practical cases, but it has O(n * m) running time in worst case.
UPD:
In case you don't need fast approaches, I corrected your code from description:
public static int timesOccur(int[] small, int big[]) {
int sum = 0;
for (int i = 0; i < big.length - small.length + 1; i++) {
int j = 0;
while (j < small.length && small[j] == big[i + j]) {
j++;
}
if (j == small.length) {
sum++;
}
}
return sum;
}
Pay attention on the inner while loop. It stops as soon as elements don't match. It's important optimization, as it makes running time almost linear for best cases.
upd2: inner loop explanation.
The purpose of inner loop is to find out if smaller array matches bigger array starting from position i. To perform that check index j is iterated from 0 to length of smaller array, comparing the element j of the smaller array with the corresponding element i + j of the bigger array. Loop proceeds when both conditions are true at the same time: j < small.length and corresponding elements of two arrays match.
So loop stops in two situations:
j < small.length is false. This means that j==small.length. Also it means that for all j=0..small.length-1 elements of the two arrays matched (otherwise loop would break earlier, see (2) below).
small[j] == big[i + j] is false. This means that match was not found. In this case loop will break before j reaches small.length
After the loop it's sufficient to check whether j==small.length to know which condition made loop to stop and hence know whether match was found or not for current position i.
This is a simple subarray matching problem. In Java you can use Collections.indexOfSublist, but you would have to box all the integers in your array. An option is to implement your own array matching algorithm. There are several options, most string searching algorithms can be adapted to this task.
Here is an optimized version based on the KMP algorithm. In the worst case it will be O(n + m), which is better than the trivial algorithm. But it has the downside of requiring extra space to compute the failure function (F).
public class Main {
public static class KMP {
private final int F[];
private final int[] needle;
public KMP(int[] needle) {
this.needle = needle;
this.F = new int[needle.length + 1];
F[0] = 0;
F[1] = 0;
int i = 1, j = 0;
while (i < needle.length) {
if (needle[i] == needle[j])
F[++i] = ++j;
else if (j == 0)
F[++i] = 0;
else
j = F[j];
}
}
public int countAt(int[] haystack) {
int count = 0;
int i = 0, j = 0;
int n = haystack.length, m = needle.length;
while (i - j <= n - m) {
while (j < m) {
if (needle[j] == haystack[i]) {
i++;
j++;
} else break;
}
if (j == m) count++;
else if (j == 0) i++;
j = F[j];
}
return count;
}
}
public static void main(String[] args) {
System.out.println(new KMP(new int[]{1, 2}).countAt(new int[]{1, 2, 3, 4, 1, 2, 1, 3}));
System.out.println(new KMP(new int[]{1, 1}).countAt(new int[]{1, 1, 1}));
}
}
Rather than posting a solution I'll provide some hints to get your moving.
It's worth breaking the problem down into smaller pieces, in general your algorithm should look like:
for each position in the big array
check if the small array matches that position
if it does, increment your counter
The smaller piece is then checking if the small array matches a given position
first check if there's enough room to fit the smaller array
if not then the arrays don't match
otherwise for each position in the smaller array
check if the values in the arrays match
if not then the arrays don't match
if you get to the end of the smaller array and they have all matched
then the arrays match
Though not thoroughly tested I believe this is a solution to your problem. I would highly recommend using Sprinters pseudocode to try and figure this out yourself before using this.
public static void main(String[] args)
{
int[] smallArray = {1,1};
int[] bigArray = {1,1,1};
int sum = 0;
for(int i = 0; i < bigArray.length; i++)
{
boolean flag = true;
if(bigArray[i] == smallArray[0])
{
for(int x = 0; x < smallArray.length; x++)
{
if(i + x >= bigArray.length)
flag = false;
else if(bigArray[i + x] != smallArray[x])
flag = false;
}
if(flag)
sum += 1;
}
}
System.out.println(sum);
}
}

Categories