Below code works fine but it is in the complexity of O(n^2). Is it possible to do it O(n) or O(log n) time.
public class TwoRepeatingElements {
public static void main(String[] args) {
Integer array[] = {4, 2, 4, 5, 2, 3, 1, 2};
findTwoRepeatingElements(array);
}
private static void findTwoRepeatingElements(Integer[] array) {
int i, j;
for(i = 0; i < array.length-1; i++) {
for(j = i+1; j < array.length-1; j++) {
if(array[i] == array[j]) {
System.out.println(array[i]);
}
}
}
}
}
Obviously you can't find it in less than O(n), since you need to scan the whole array.
You can use hastable for a O(n) solution.
Just insert your elements in a hastable as you go and stop when the element you are to insert is already there.
private static void findTwoRepeatingElements(Integer[] array) {
Set<Integer> set = new HashSet<Integer>();
for(int a : array) {
if(!set.add(a)) {
System.out.println(a);
break;
}
}
}
You can sort the array and then just look for two equal numbers in adjacent positions.
This solution runs in O(n) time, notice that if you only need to find one repeated element, you can exit the loop as soon as you find it:
private static void findTwoRepeatingElements(Integer[] array) {
Set<Integer> seen = new HashSet<Integer>();
for (Integer i : array) {
if (seen.contains(i))
System.out.println(i);
else
seen.add(i);
}
}
EDIT
If you need to print the repeated elements only once, this solution uses a little more memory since two sets are needed, but it's still O(n). Take a look at this:
private static void findTwoRepeatingElements(Integer[] array) {
Set<Integer> seen = new HashSet<Integer>();
Set<Integer> repeated = new HashSet<Integer>();
for (Integer i : array)
if (!seen.add(i) && repeated.add(i))
System.out.println(i);
}
Create a temporary hashmap and put all values you encounter into this. The average look up time for a hashmap is O(1), thus you'd end with O(n).
O(log n) is absolutely impossible, since you need to iterate over the entire array at least once.
If you know beforehand what range of integers are possible, and it's a relatively small range, you can use a boolean[] to keep track of what integers you've already seen. That would be O(n+k), where k is the size of the range, and therefore O(n) if k is in O(n). Otherwise, you can use a HashSet<Integer>, though that would not be guaranteed O(n) time.
This can be reduced to O(n)
int previous =array[0];
for(int i=1; i less than array.length; i++) {
if (previous == array[i] return true;
previous =array[i];
}
return false // outside of loop.
Forgive the formatting I'm on my mobile
Similar to Peter's answer, but using the API better and thus with less code:
static Integer findFirstRepeatedElement(Integer[] array) {
Set<Integer> set = new HashSet<Integer>();
for(Integer a : array) {
if(!set.add(a)) // returns false if the element is already in the set
return a;
}
return null;
}
Edited: I notice he has now fixed his previous non-leet implementation
Related
I have a program that sums the common elements of two arrays. For that I used two for loops and if I have three then I could use three for loops. But how to sum the common elements of n number of arrays where n is coming during run time.
I don't know how to change the number of loops during run time or is there any other relevant concept for this ?
Here is the code I've tried for summing twoarrays:
import java.util.Scanner;
public class Sample {
public static void main(String... args)
{
Scanner sc=new Scanner(System.in);
int arr1[]={1,2,3,4,5},arr2[]={4,5,6,7,8},sum=0;
for (int i=0;i<arr1.length;i++)
{
for (int j=0;j<arr2.length;j++)
{
if (arr1[i]==arr2[j])
{
sum+=(arr1[i]);
}
}
}
}
}
There can be different implementation for that. You can use the following approach. Here is the pseudo code
use a 2D array to store the array. if the number of array is n and size is m then the array will be input[n][m]
Use a ArrayList commonItems to store the common items of. Initiate it with the elements of input[0]
Now iterate through the array for i = 1 to n-1. compare with every input[i], store only the common items of commonItems and input[i] at each step. You can do it by converting the input[i] into a list and by using retainAll method.
At the end of the iteration the commonItem list will contains the common numbers only. Now sum the value of this list.
There is actually a more general method, that also answers the question "how to change the number of loops during run time?".
The general question
We are looking for a way to implement something equivalent to this:
for (i1 = 0; i1 < k1; i1++) {
for (i2 = 0; i2 < k2; i2++) {
for (i3 = 0; i3 < k3; i3++) {
...
for (in = 0; in < kn; in++) {
f(x1[i1], x2[i2], ... xn[in]);
}
...
}
}
}
where, n is given at runtime and f is a function taking a list of n parameters, processing the current n-tuple.
A general solution
There is a general solution, based on the concept of recursion.
This is one implementation that produces the desired behavior:
void process(int idx, int n, int[][] x, int[] k, Object[] ntuple) {
if (idx == n) {
// we have a complete n-tuple,
// with an element from each of the n arrays
f(ntuple);
return;
}
// this is the idx'th "for" statement
for (int i = 0; i < k[idx]; i++) {
ntuple[idx] = x[idx][i];
// with this recursive call we make sure that
// we also generate the rest of the for's
process(idx + 1, n, x, k, ntuple);
}
}
The function assumes that the n arrays are stored in a matrix x, and the first call should look like this:
process(0, n, x, k, new Object[n]);
Practical considerations
The solution above has a high complexity (it is O(k1⋅k2⋅..⋅kn)), but sometimes it is possible to avoid going until the deepest loop.
Indeed, in the specific problem mentioned in this post (which requires summing common elements across all arrays), we can skip generating some tuples e.g. if already x2[i2] ≠ x1[i1].
In the recursive solution, those situations can easily be pruned. The specific code for this problem would probably look like this:
void process(int idx, int n, int[][] x, int[] k, int value) {
if (idx == n) {
// all elements from the current tuple are equal to "value".
// add this to the global "sum" variable
sum += value;
return;
}
for (int i = 0; i < k[idx]; i++) {
if (idx == 0) {
// this is the outer "for", set the new value
value = x[0][i];
} else {
// check if the current element from the idx'th for
// has the same value as all previous elements
if (x[idx][i] == value) {
process(idx + 1, n, x, k, value);
}
}
}
}
Assuming that the index of the element is not important: a[1] = 2 and a[5] = 2, you only need two nested loops.
First you need to put n-1 arrays in a list of sets. Then loop over nth array and check if each element exists in all of the sets in the list. If it does exist then add to total.
My objective is to remove all negative numbers from an array in Java.
I have written the below code. How do I improve the complexity of code or is there a good algorithm?
public static void main(String[] args) {
int[] array = { 1, -3, 4, -9, 3, 4, 70, -10, 0, 7 };
System.out.println(Arrays.toString(removeNegativeNumbers(array)));
}
public static int[] removeNegativeNumbers(int[] num) {
List<Integer> list = new ArrayList<>();
for (int n : num) {
if (n >= 0) {
list.add(n);
}
}
int[] result = new int[list.size()];
for (int i = 0; i < result.length; i++) {
result[i] = list.get(i).intValue();
}
return result;
}
What about Java 8 streams?
Arrays.stream(num).filter(s -> s >= 0).toArray();
How do I improve the complexity of code or is there a good algorithm?
Here is a linear O(n) algorithm with constant space (neglecting the space we need for output array). When an element is non-negative, copy the element and advance both output array and input array seeker. And when the element is negative, advance only the input array seeker(indx) and avoid copying to output array.
public static int[] removeNegativeNumbers(int[] num) {
int[] output = new int[num.length];
int k = 0;
for(int i = 0; i < num.length; i++) {
if(num[i] >= 0) {
output[k++] = num[i];
}
}
return Arrays.copyOfRange(output, 0, k);
}
Space Efficient Solution
You can make the algorithm in-place by transforming the input array to hold output like insertion sort way to avoid the space overhead of output array.
public static int removeNegativeNumbers(int[] num) {
int k = 0;
for(int i = 0; i < num.length; i++) {
if(num[i] >= 0) {
num[k++] = num[i];
}
}
// Now input array is holding the output data
// Return the length of output array
return k;
}
// Usage: int newLen = removeNegativeNumbers(array);
This is called two pointers technique, very simple yet useful to solve many classical puzzles like Array de-duplication, merging two sorted arrays, intersection of two sorted arrays etc.
I don't think we can get better in terms of efficiency than #kaidul-islam answer (and #user6904265 in terms of conciseness).
I'm just adding a solution that should have some value in a very specific scenario, where negatives rarely appear and array is very large.
Basic idea is to defer the actual copy until a negative value is found and then copy with System.arraycopy. In case no negative is found, the source array would be returned.
import java.util.*;
public class NotNegativeTest {
public static void main(String[] args) {
int[] array = { 1, -3, 4, -9, 3, 4, 70, -10, 0, 7 };
System.out.println(Arrays.toString(removeNegativeNumbers(array)));
}
public static int[] removeNegativeNumbers(int[] num) {
int[] output = new int[num.length];
int k = 0;
int i = 0;
int last=-1;
int howmany=0;
while(i < num.length) {
if(num[i] < 0) {
howmany=i-last-1;
switch(howmany) {
case 0: break;
case 1:
output[k]=num[last+1];
k++;
break;
default:
System.arraycopy(num, last+1, output, k, howmany);
k+=howmany;
}
last=i;
}
i++;
}
if (last>=0) {
if(last!=i-1) {
howmany=i-last-1;
System.arraycopy(num, last+1, output, k, howmany);
k+=howmany;
}
} else {
return num;
}
return Arrays.copyOfRange(output, 0, k);
}
}
I've found the time to write a JMH microbenchmark.
I've used used these configurations:
Options opts = new OptionsBuilder()
.include(MyBenchmark.class.getSimpleName())
.mode(Mode.AverageTime)
.warmupIterations(1)
.warmupTime(TimeValue.seconds(5))
.measurementIterations(10)
.measurementTime(TimeValue.seconds(5))
.jvmArgs("-server")
.forks(1)
.build();
new Runner(opts).run();
(disclaimer: my first JMH test, so if someone has some suggestions, I'll be glad to change it and update the results)
And here are the results:
# Run complete. Total time: 00:02:54
Benchmark Mode Cnt Score Error Units
MyBenchmark.testMethodUser6904265 avgt 10 0,201 ± 0,040 s/op
MyBenchmark.testMethodInsac avgt 10 0,093 ± 0,022 s/op
MyBenchmark.testMethodKaidul avgt 10 0,124 ± 0,029 s/op
Now, before cheering me, please take a look to how biased the test was:
int[] array = new int[10000000];
array[0]=-5;
array[10000]=-3;
array[40000]=-3;
array[8000000]=-3;
int[] answer=NotNegativeTest.removeNegativeNumbers(array);
So here the thing to notice it is not that my method won (the test was written for my method to win :-) but how close the generic kaidul-islam method was to mine even in this extreme scenario.
UPDATED: here is the link to the jmh benchmark I wrote so you can verify more realistic scenario (if someone finds issues with how I setup the test, please let me know). There is a depenendency on Trove for a test I've done on another answer.
This will do it in-place with a single iteration:
Hold 2 indexes: src and dst on the original array. both are initialized to 0.
when a number is positive, copy it from num[src] to num[dst] and advance both indexes
when a number is negative, just advance src.
return the original array with dst as its new size.
public static int removeNegativeNumbers(int[] num) {
int dst=0;
for (int src=0 ; src<num.length ; ++src)
if (num[src]>=0)
num[dst++] = num[src];
return dst;
}
Follow the below code (Java 8)
int test[] = new int[] { 15, -40, -35, 45, -15 };
// here we can take the test array in to stream and filter with condition (>=0).
int[] positives = Arrays.stream(test).filter(x -> x >= 0).toArray();
System.out.println("Here is the positive array elements");
for (int i : positives) {
System.out.print(i + "\t");
}
Since you will necessarily need to look at each individual element to determine if it is less than 0, the runtime must be at least O(n). Since the space needed to store the input is O(n), the space is at least O(n). Your solution runs in O(n) time with O(n) complexity, therefore no solution can have better space or runtime complexity than your solution
We can, however, get better results if we assume the array is sorted. Then, we do a binary search for 0. If we have a way to return the sub-array with constant time (e.g. pointer magic in C, or by simply returning the start index to be read), then the algorithm would have O(log n) time.
Use iterator
Iterator<Integer> itr = objArray.iterator();
while(itr.hasNext()) {
Integer next = itr.next();
if(next < 0) {
itr.remove();
}
}
public static int[] removeNegativeNumbers(int[] num) {
List<Integer> list = new ArrayList<>();
for (int n : num) {
if (n >= 0) {
list.add(n);
}
}
return list.toArray(new int[list.size()]);
}
I am trying to solve the below 'codility' exercise:
A zero-indexed array A consisting of N different integers is given. The array contains integers in the range [1..(N + 1)], which means that exactly one element is missing.
Your goal is to find that missing element.
Write a function:
class Solution { public int solution(int[] A); }
that, given a zero-indexed array A, returns the value of the missing element.
For example, given array A such that:
A[0] = 2
A[1] = 3
A[2] = 1
A[3] = 5
the function should return 4, as it is the missing element.
Assume that:
N is an integer within the range [0..100,000];
the elements of A are all distinct;
each element of array A is an integer within the range [1..(N + 1)].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(1), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
I came up with two solutions:
1) Gives 100%/100%
class Solution {
public int solution(int[] A) {
int previous = 0;
if (A.length != 0) {
Arrays.sort(A);
for (int i : A) {
if (++previous != i) {
return previous;
}
}
}
return ++previous;
}
}
2) Gives an error WRONG ANSWER, got 65536 expected 100001
class SolutionHS {
public int solution(int[] A) {
int previous = 0;
HashSet<Integer> hs = new HashSet<>();
if (A.length != 0) {
for (int a : A) {
hs.add(a);
}
for (Integer i : hs) {
if (++previous != i) {
return previous;
}
}
}
return ++previous;
}
}
My question is:
Shouldn't both approaches (using hashset and Arrays.sort) work the same way?
If not can you tell me what the difference is?
HashSet is not sorted, so when you iterate over the elements of the Set, you don't get them in an ascending order, as your code expects. If you used a TreeSet instead of HashSet, your code would work.
The HashSet solution will give the correct answer if you change the second loop to :
for (int i = 0; i <= A.length; i++) {
if (!hs.contains(i)) {
return i;
}
}
This loop explicitly checks whether each integer in the relevant range appears in the HashSet and returns the first (and only one) which doesn't.
Anyway, both your implementations don't meet the O(n) running time and O(1) space requirements.
In order you meet the required running time and space, you should calculate the sum of the elements of the array and subtract that sum from (A.length+1)*A.length/2.
Background: Very new at Java, have little understanding. Would prefer a "point in the right direction" with explanation, if possible, than a copy/paste answer without explanation. If I want to stop being a novice, I need to learn! :)
Anyway, my goal is, as simply as possible, to be given 2 arrays numberList and winningNumbers, compare them, and return the percentage that numberList matches winningNumbers. Both array lengths will always be 10.
I have no idea where to start. I have been googling and going at this for 2 hours. My idea is to write a for loop that compares each individually integer in a string to one in the other, but I am not sure how to do that, or if there is a simpler method. I have little knowledge of arrays, and the more I google the more confused I become.
So far the only thing I have is
public double getPercentThatMatch(int[] winningNumbers) {}
numberList is preset.
one way you could approach it is to:
1) convert both lists to sets.
2) subtract one from the other. ie if 4 are the same, the resulting set will have the 6 values not the same
3) 10 - (size of resulting set) * 100 = %
Here's a runnable example of how you would compare the two arrays of ints to get a percent match.
public class LotteryTicket {
int[] numberList;
LotteryTicket(int... numbers) {
numberList = numbers;
}
public int getPercentThatMatch(int[] winningNumbers) {
Arrays.sort(numberList);
Arrays.sort(winningNumbers);
int i = 0, n = 0, match = 0;
while (i < numberList.length && n < winningNumbers.length) {
if (numberList[i] < winningNumbers[n]) {
i++;
} else if (numberList[i] > winningNumbers[n]) {
n++;
} else {
match++;
i++;
n++;
}
}
return match * 100 / winningNumbers.length;
}
public static void main(String[] args)
{
int[] winningNumbers = { 12, 10, 4, 3, 2, 5, 6, 7, 9, 1 };
LotteryTicket ticket = new LotteryTicket(5, 2, 6, 7, 8, 4, 3, 1, 9, 0);
int percentMatching = ticket.getPercentThatMatch(winningNumbers);
System.out.println(percentMatching + "%");
}
}
Output:
80%
Since you wanted to be pointed in the right direction, rather than havving proper code, and assuming you want to use arrays to solve the problem, try to put something like this in your method:
(loop through arrayA){
(loop through arrayB){
if (current arrayA number is equal to current arrayB number){
then increase match counter by one, since this exists.
also break out of current arrayB loop. (Check next arrayA now.)
}
}
}
When done: return 100*matchCount/totalCount, as a double
So for every index in one array, you check against every other index of the other array. Increase a counter each time there's a match, and you'll be able to get a ratio of matches. If you use an integer as a counter, remember that division with integers acts funky, so you'd need to throw to a double:
double aDoubleNumber = (double) intNumber / anotherIntNumber
The problem would be easier if we consider them set. Let you have two set -
Set<Integer> s1 = //a HashSet of Integer;
Set<Integer> s2 = //a HashSet of Integer;
Now make a copy of s1 for example s11 and do the following thing -
s1.retainAll(s2);
Now s1 contains only element of both sets - that is the intersection.
After that you can easily calculate the percentage
Edit: You can convert the array to a set easily by using the following code snippet (I am assuming you have array of int) -
Set<Integer> s1 = new HashSet<Integer>(Arrays.asList(somePrimiteiveIntArray));
I think this trick will works for other primitive type also.
Hope this will help.
Thanks a lot.
I am going to attempt to beat a dead horse and explain the easiest (conceptual) way to approach this problem I will include some code but leave a lot up to interpretation.
You have two arrays so I would change the overall method to something like this:
public double getPercentage(int[] arrayA, int[] arrayB) {
double percentage=0;
for(/*go through the first array*/) {
for(/*go through second array*/) {
if(arrayA[i]==arrayB[j]) { /*note the different indices*/
percentage++; /*count how many times you have matching values*/
/* NOTE: This only works if you don't have repeating values in arrayA*/
}
}
}
return (percentage/arrayA.length)*100; /*return the amount of times over the length times 100*/
}
You are going to move through the first array with the first loop and the second array with the second loop. So you go through every value in arrayB for each value in arrayA to check.
In my approach I tried storing the winning numbers in a Hashset (one pass iteration, O(n) )
And when iterating on the numberList, I would check for presence of number in Hashset and if so, I will increment the counter. (one pass iteration, so O(n) )
The percentage is thus calculated by dividing the counter with size of array.
See if the sample code makes sense:
import java.util.HashSet;
public class Arraycomparison {
public static void main(String ... args){
int[] arr0 = {1,4,2,7,6,3,5,0,3,9,3,5,7};
int[] arr1 = {5,2,4,1,3,7,8,3,2,6,4,4,1};
HashSet set = new HashSet();
for(int j = 0; j < arr1.length; j++){
set.add(arr1[j]);
}
double counter = 0;
for(int i = 0; i < arr0.length; i++){
if(set.contains(arr0[i])){
counter++;
}
}
System.out.println("Match percentage between arrays : " + counter/arr0.length*100);
}
}
You should use List over array, because that's a convenient way, but with array:
public class Winner {
public static void main(String... args) {
double result = getPercentThatMatch(new int[]{1,2,3,4,5}, new int[]{2,3,4,5,6});
System.out.println("Result="+result+"%");
}
public static double getPercentThatMatch(int[] winningNumbers,
int[] numberList) { // it is confusing to call an array as List
int match = 0;
for (int win : winningNumbers) {
for (int my : numberList ){
if (win == my){
System.out.println(win + " == " + my);
match++;
}
}
}
int max = winningNumbers.length; // assume that same length
System.out.println("max:"+max);
System.out.println("match:"+match);
double devide = match / max; // it won't be good, because the result will be intm so Java will trunc it!
System.out.println("int value:"+devide);
devide = (double) match / max; // you need to cast to float or double
System.out.println("float value:"+devide);
double percent = devide * 100;
return percent;
}
}
Hope this helps. ;)
//For unique elements
getpercentage(arr1, arr2){
res = arr1.filter(element=>arr2.includes(element))
return res.lenght/arr2.lenght * 100;
}
//For duplicate elements
getpercentage(arr1, arr2){
const setA = Set(arr1);
const setB = Set(arr2);
Let res = [ ];
for(let i of setB){
if(setA.has(i)){
res.push(i);
}
}
return res.lenght/setA.size* 100;
Im a beginner in Java and I had this doubt. Is it possible to use the Enhanced for loop in Java on an ArrayList, but start at the specified point rather than ArrayList[0].
For eg. ArrayList<Integer> calc = new ArrayList<Integer>;
// calc contains {0,1,2,3,4,5,6,7}
Can I use enhanced for loop and start iterating from calc[2] rather than calc[0]?? If possible, how can I do that?
In my particular case, using a enhanced for loop would be better, rather than a normal for loop.
The best way in Java would be like this:
for (Integer i : calc.subList(start, calc.size()) {
...
}
subList is an efficient view of the original list, so it's almost exactly what you need.
UPDATE
OK, motivated by Mikera's comments, I benchmarked it on jmh. This is the benchmarked code:
import org.openjdk.jmh.annotations.GenerateMicroBenchmark;
public class Benchmark1
{
static final List<Integer> list = new ArrayList(asList(1,2,3,4,5,6,7,8,9,10));
static { for (int i = 0; i < 5; i++) list.addAll(list); }
#GenerateMicroBenchmark
public long testIterator() {
long sum = 0;
for (int i : list) sum += i;
return sum;
}
#GenerateMicroBenchmark
public long testIndexed() {
long sum = 0;
for (int i = 0; i < list.size(); i++) sum += list.get(i);
return sum;
}
#GenerateMicroBenchmark
public long testSublistIterator() {
long sum = 0;
for (int i : list.subList(1, list.size())) sum += i;
return sum;
}
#GenerateMicroBenchmark
public long testIndexedSublist() {
long sum = 0;
final List<Integer> l = list.subList(1, list.size());
for (int i = 0; i < l.size(); i++) sum += l.get(i);
return sum;
}
}
And these are the results:
Benchmark ops/msec
-------------------------
Indexed 1860.982
IndexedSublist 1642.059
Iterator 1818.657
SublistIterator 1496.994
Conclusions:
enhanced for on the main list is as fast as indexed iteration, once past the initialization cost;
traversal of the sublist is somewhat slower than of the main list, and iteration is somewhat slower than indexed traversal;
all the differences are negligible for all practical purposes.
You're stuck using a traditional loop here...
for (int i = 2; i < calc.size(); i++) {
Integer x = calc.get(i);
}
Well, unless you're willing to create a temporary subList just for using an enhanced for loop, which is fine, because sublists are views of the original list and don't create a new list object:
for (Integer x : calc.subList(2, calc.size())) {
}
for(Item e : list.subList(1, list.size())) {
// ...
}
You could iterate through the sublist, as below:
for (Integer integerMember : calc.subList(2, calc.size()) {
// operation here
}
It should be noted that the enhanced for loop is less efficient for ArrayList then standard indexing. This is because we have to create an Iterator object and call hasNext and next on it on each step of the loop, causing unnecessary overhead.
For this reason I would recommend indexing in the traditional way rather than using the sublist approach.