Find maximum element from two arrays - java

I need to find maximum element from two arrays
int arr1[]={20,65,23056,67,678};
int arr2[]={76,23,4545,98,90909};
My code is giving output but i think it's complexity is high.Below are my code.Is it good or it need improvement?
int arr1[]={20,65,23056,67,678};
int arr2[]={76,23,4545,98,90909};
int len1=arr1.length;
int len2=arr2.length;
int max1=arr1[0];
for(int i=0;i<len1;i++){
if(arr1[i]>max1){
max1=arr1[i];
}
}
int max2=arr2[0];
for(int j=0;j<len2;j++){
if(arr2[j]>max2){
max2=arr2[j];
}
}
if(max1>max2){
System.out.print("max element is:"+max1);
}
else{
System.out.print("Max element is: "+max2);
}
Output :- 90909

Try this
Integer arr1[]={20,65,23056,67,678};
Integer arr2[]={76,23,4545,98,90909};
Integer max = Stream.concat(Arrays.stream(arr1), Arrays.stream(arr2)).max(Comparator.comparing(Integer::valueOf)).get();

You can use Java streams to achieve this. If you want to avoid boxing values to Integer and you want to get primitive integer directly use IntStream::concat and and IntStream::of :
int[] arr1 = {20, 65, 23056, 67, 678};
int[] arr2 = {76, 23, 4545, 98, 90909};
int max = IntStream
.concat(IntStream.of(arr1), IntStream.of(arr2))
.max()
.getAsInt();

Even if you don't want to deal with streams, you can still improve it a bit:
int arr1[] = { 20, 65, 23056, 67, 678 };
int arr2[] = { 76, 23, 4545, 98, 90909 };
int len = arr1.length > arr2.length ? arr1.length : arr2.length;
int max = 0;
for (int i = 0; i < len; i++) {
if (arr1.length > i && arr1[i] > max) {
max = arr1[i];
}
if (arr2.length > i && arr2[i] > max) {
max = arr2[i];
}
}
System.out.print("max element is:" + max);```

If we consider the length of the first and second arrays as n and m respectively. Your solution is taking the complexity of O(n+m). It's the best case, as the arrays are not sorted.

Other answers here focus on Streams (which is perfectly fine - and acceptable).
However, if you have limitations on usage of stream (JDK 7 and earlier), you could put the arrays in a TreeSet with Collections.reverseOrder to sort the elements in descending order. The 0th index will be the largest or mac element from the union of the arrays.
Edit: Note that TreeSet doesn't persist duplicates, so you're better off than storing duplicates in arrays. In the worst case, if two arrays of 5 elements each contained 9 duplicates, the TreeSet would only house 2 elemens (the unique one and the other being the duplicate one), as against two arrays containing 10 elements.

Related

array with random ints but no duplicates and first number showing [duplicate]

This question already has answers here:
Creating random numbers with no duplicates
(20 answers)
Closed 1 year ago.
This is probably already asked, but it is a little difficult for me to understand. I created a for loop to add random integers into my array, but when the integer is already in the array, restart the loop. But I keep on getting the same integers into the array + when there already is a duplicate, the array size increases. Does anyone know what I'm doing wrong?
Random r = new Random();
int[] tes = new int[5];
for (int i = 0; i < tes.length; i++) {
int q = r.nextInt(10);
for (int j = 0; j < i; j++) {
if (q == tes[j]){
i=i-1;
}
}
tes[i] = q;
System.out.println(tes[i]);
}
and the output:
If you want a collection without duplicates you should use a Set:
Random r = new Random();
int desirableSize = 5;
Set<Integer> uniques = new HashSet<>(desirableSize);
while(uniques.size() < desirableSize){
uniques.add(r.nextInt(10));
}
System.out.println(uniques);
The add method already ensures that a value is not added if it already exist on the set.
boolean add(E e)
Adds the specified element to this set if it is not already present (optional operation).
I have used HashSet, however if the insertion order is important for you, use instead LinkedHashSet:
As pjs have pointed out the aforementioned approach is good when:
desirableSize is much less than the pool size, but if the
desirableSize is a substantial proportion of pool size you're better
off shuffling the pool and selecting the first desirableSize elements.
Something as follows:
int start = 0;
int end = 10;
int size = 5;
List<Integer> collect = IntStream.rangeClosed(start, end)
.boxed()
.limit(size)
.collect(Collectors.toList());
Collections.shuffle(collect);
System.out.println(collect);
The rational is the following (quoting pjs):
With rejection-based schemes such as repeated attempts to add to a
set, the expected number of iterations is O(poolsize *
log(desirableSize)) with O(desirableSize) storage for the set.
Shuffling is O(poolsize) but requires O(poolsize) storage for the
shuffle. As desirableSize -> poolsize, shuffling wins on expected
iterations and becomes competitive on storage. With partial shuffling
implementations, the number of iterations for shuffling is
O(desirableSize) although the storage remains the same.
Or more informally, the higher it is the unique finite set of numbers that will be pickup from a finite set of possible numbers, the more desirable it is to use the second approach.
For instance, if one generates numbers from 0 to 1000 and is only interested in 5 numbers, since the probability of picking randomly the same numbers is lower, one is better off with the first approach. However, if you would be (instead) interested in 800 numbers, then one would be better off generating and shuffling the 1000 numbers, and extracting the 800 unique values from them.
Memory-wise the first approach is better then second approach, however performance-wise it depends in the context as we have already described.
i dont see a problem.
Your System.out.println(tes[i]); is in loop
your array has only following ints: 5,9,2,7,1
make println in own loop
for (int i = 0; i < tes.length; i++) {
System.out.println(tes[i]);
}
because you make i=i-1; one value is printed many times
I managed to solve it in a different way:
List<Integer> tes = new ArrayList<>(5);
Random r = new Random();
for (int i = 0; i < 5; i++) {
int testNummer = r.nextInt(10);
if(!tes.contains(testNummer)) {
tes.add(testNummer);
System.out.println(testNummer);
}else{
i=i-1;
}
}
this way is more efficient, I have noticed.
Some logic problem
Increment i variable when you store value in array and don't decrement i variable just break inner loop when found duplicate.
when duplicate found then restart outer loop. use if else condition for that
try below code and for simple understanding i have changed outer loop in while
int i = 0;
while(i<5)
{
int q = r.nextInt(10);
System.out.println("random value generated"+ q );
int j=0;
for (;j < i; j++)
{
if (q == tes[j])
{
System.out.println("duplicate value found"+ q );
break;
}
}
if(j!=i)
{
continue;
}
else
{
if(j==i)
{
tes[i] = q;
i=i+1;
}
}
System.out.println("value at "+ tes[i]);
}
If you want an easy way to generate unique values you can do it with a stream.
Random r = new Random();
int minVal = 1;
int upperBound = 20;
int count = 10;
As long as count is less than upperBound - minVal it will finish without duplicates. For very large counts with the appropriate range, it may take some time.
int[] unique = r.ints(minVal, upperBound).distinct().limit(count).toArray();
System.out.println(Arrays.toString(unique));
Prints something like this.
[14, 1, 7, 13, 5, 16, 2, 8, 12, 4]
An easy way to generate random numbers of a fixed range is to simply shuffle the array.
Integer[] vals = new Integer[20];
for (int i = 0; i < vals.length; i++) {
vals[i] = i+1;
}
// Object array will be shuffle since it backs up the list.
Collections.shuffle(Arrays.asList(vals));
System.out.println(Arrays.toString(vals));
Prints something like
[7, 20, 5, 10, 17, 18, 3, 13, 11, 1, 2, 8, 4, 9, 19, 12, 15, 16, 6, 14]

Is there a better way to write this code? (Finding lowest number AND greatest number in array) [Java]

So I have this piece of code which basically is trying to find the largest number in an array and the smallest number (here it's ticket price). But I find myself writing two for loops, I was wondering if there was a more efficient way to write this?
/** Setting cheapestCost to the index of the cheapest transport obj*/
for(int i = 0; i < 15; i++) {
if(allTransports[cheapestCost].getTicketPrice() > allTransports[i].getTicketPrice()) {
cheapestCost = i;
}
}
/** Setting greatestCost to the index of the most expensive transport obj*/
for(int i = 0; i < 15; i++) {
if(allTransports[greatestCost].getTicketPrice() < allTransports[i].getTicketPrice()) {
greatestCost = i;
}
}
Thanks!
It seems to me you can just combine those two loops:
for(int i = 0; i < 15; i++) {
int price = allTransports[i].getTicketPrice();
if(allTransports[cheapestCost].getTicketPrice() > price) {
cheapestCost = i;
}
if(allTransports[greatestCost].getTicketPrice() < price) {
greatestCost = i;
}
}
Why dont use array sort ?
Int[] Tickets = new int[TicketsPrice.length]
For(int i =0;i < Tickets.length ; i++){
Tickets[i] = TicketsPrice.getPrice();
}
Int[] Arr = Arrays.sort(Tickets)
Arr[0] \\ => smallest number
Arr[Arr.length -1] \\=> largest number
There is a trick that reduces the number of comparisons you have to do. Divide the array into pairs, and make a comparison in each pair. The higher number in the pair is a candidate for highest element, so make one compare there. The lower number in the pair is a candidate for lowest element, so make one compare there. This costs you three compares per two numbers, whereas the straightforward way costs you two compares per number or four compares per two numbers.
Whether it’s any better is a matter of taste. You may use a stream operation:
/** Setting cheapestCost to the index of the cheapest transport obj*/
int cheapestCost = IntStream.range(0, 15)
.boxed()
.min(Comparator.comparing(i -> allTransports[i].getTicketPrice()))
.orElseThrow();
Similarly for the most expensive transport ticket, just use max() instead of min().
One simple way, you should sort the array by ascending of ticket price then get the first and last element.
But do not change the original order of the array, just store the sorted array in a new variable.
Transport[] allTransports = {new Transport(), new Transport()};
List<Integer> naturalSortedPrices =
Arrays.stream(allTransports).map(Transport::getTicketPrice).sorted()
.collect(Collectors.toList());
int cheapestCost = naturalSortedPrices.get(0);
int greatestCost = naturalSortedPrices.get(naturalSortedPrices.size() - 1);

Count numbers with same digits in a sorted int array in O(log n) time

I came across an interview question that required the candidate to count all numbers in an array with the same digits.
for example:
Count all numbers that share the same digits with int input = 394
int[] arr = {1, 14, 101, 349, 439, 745, 934}
the function would return 3, since 439, 934, 349 share the same digits.
The question is how do you solve this in O(log n) time? Im still new to the Big O concept and apart from O(n) and O(n^2)... i am having trouble understanding how to archieve O(log n).
My first thought was as follows:
I would calculate the sum of digits of all elements in the array. If the sum is equal they contain of the same of the digits as the input number.
int counter = 0;
while (num > 0) {
int digitSum += num % 10;
num = num / 10;
}
for(int i = 0; i < arr.length; i++) {
int k = arr[i];
while (k > 0) {
int sumOfDigits += k % 10;
k = k/10;
}
if(sumOfDigits == digitSum) {
counter++;
}
}
I know this would take at least O(n) time but im having trouble finding a better solution.
The best answer was given by Andy Turner and JB Nizet but unfortunately only as a comment:
For this to work we must assume: the size of the input number is bounded, the integers in the array are disjoint and n is the number of elements in the array.
Compute all permutations of the input number digits. Some of the permutations may be the same if the number has repeated digits, take them only once. This takes O(1) time and the number of permutations is also O(1).
For each permutation look up the corresponding number in the array using binary search and count all the hits. This takes O(log n).
In total you get a run time of O(log n).
Note that this is only practical if the bound on the input number is rather low. If the input number can have say 20 digits it is much better to use an O(n) method unless n is really huge.
You can preprocess the array to construct a Map, by "string representing the sorted digits" of the numbers in an array that map to that normalized representation. After that step, individual lookups are O(1) or O(log(n)) depending on the map chosen. It doesn't even matter how many numbers match, because you're just returning a preconstructed array.
So the lookup can indeed be made very fast. But only if you either discount the preprocessing step, or amortize it over many lookups.
This solution is almost O(n) as number of digit in the input is very small compare to the given array size (n).
Idea is to get the minimum possible number from each element and compare with the corresponding value of the input number
public static void main(String []args){
int input = 394;
int[] arr = {1, 14, 101, 349, 439, 745, 934};
int ans = 0;
int hold = getMin(input);
for(int i = 0; i < arr.length; i++)
{
if(hold == getMin( arr[i] ))
{
ans++;
}
}
System.out.println(ans);
}
public static int getMin(int n)
{
int hold[] = new int[10];
while( n > 0)
{
hold[n % 10]++;
n /= 10;
}
int ans = 0;
for(int i = 0; i < hold.length; i++)
{
while(hold[i] > 0)
{
ans = ans * 10 + i;
hold[i]--;
}
}
return ans;
}

For N equally sized arrays with integers in ascending order, how can I select the numbers common to arrays?

I was asked an algorithmic question today in an interview and i would love to get SO members' input on the same. The question was as follows;
Given equally sized N arrays with integers in ascending order, how would you select the numbers common to all N arrays.
At first my thought was to iterate over elements starting from the first array trickling down to the rest of the arrays. But then that would result in N power N iterations if i am right. So then i came up with a solution to add the count to a map by keeping the element as the key and the value as the counter. This way i believe the time complexity is just N. Following is the implementation in Java of my approach
public static void main(String[] args) {
int[] arr1 = { 1, 4, 6, 8,11,15 };
int[] arr2 = { 3, 4, 6, 9, 10,16 };
int[] arr3 = { 1, 4, 6, 13,15,16 };
System.out.println(commonNumbers(arr1, arr2, arr3));
}
public static List<Integer> commonNumbers(int[] arr1, int[] arr2, int[] arr3) {
Map<Integer, Integer>countMap = new HashMap<Integer, Integer>();
for(int element:arr1)
{
countMap.put(element, 1);
}
for(int element:arr2)
{
if(countMap.containsKey(element))
{
countMap.put(element,countMap.get(element)+1);
}
}
for(int element:arr3)
{
if(countMap.containsKey(element))
{
countMap.put(element,countMap.get(element)+1);
}
}
List<Integer>toReturn = new LinkedList<Integer>();
for(int key:countMap.keySet())
{
int count = countMap.get(key);
if(count==3)toReturn.add(key);
}
return toReturn;
}
I just did this for three arrays to see how it will work. Question talks about N Arrays though i think this would still hold.
My question is, is there a better approach to solve this problem with time complexity in mind?
Treat as 3 queues. While values are different, "remove" (by incrementing the array index) the smallest. When they match, "remove" (and record) the matches.
int i1 = 0;
int i2 = 0;
int i3 = 0;
while (i1 < array1.size && i2 < array2.size && i3 < array3.size) {
int next1 = array1[i1];
int next2 = array2[i2];
int next3 = array3[i3];
if (next1 == next2 && next1 == next3) {
recordMatch(next1);
i1++;
i2++;
i3++;
}
else if (next1 < next2 && next1 < next3) {
i1++;
}
else if (next2 < next1 && next2 < next3) {
i2++;
}
else {
i3++;
}
}
Easily generalized to N arrays, though with N large you'd want to optimize the compares somehow (NPE's "heap").
I think this can be solved with a single parallel iteration over the N arrays, and an N-element min-heap. In the heap you would keep the current element from each of the N input arrays.
The idea is that at each step you'd advance along the array whose element is at the top of the heap (i.e. is the smallest).
You'll need to be able to detect when the heap consists entirely of identical values. This can be done in constant time as long as you keep track of the largest element you've added to the heap.
If each array contains M elements, the worst-case time complexity of the would be O(M*N*log(N)) and it would require O(N) memory.
try
public static Set<Integer> commonNumbers(int[] arr1, int[] arr2, int[] arr3) {
Set<Integer> s1 = createSet(arr1);
Set<Integer> s2 = createSet(arr2);
Set<Integer> s3 = createSet(arr3);
s1.retainAll(s2);
s1.retainAll(s3);
return s1;
}
private static Set<Integer> createSet(int[] arr) {
Set<Integer> s = new HashSet<Integer>();
for (int e : arr) {
s.add(e);
}
return s;
}
This is how I learned to do it in an algorithms class. Not sure if it's "better", but it uses less memory and less overhead because it iterates straight through the arrays instead of building a map first.
public static List<Integer> commonNumbers(int[] arr1, int[] arr2, int[] arr3, ... , int[] arrN) {
List<Integer>toReturn = new LinkedList<Integer>();
int len = arr1.length;
int j = 0, k = 0, ... , counterN = 0;
for (int i = 0; i < len; i++) {
while (arr2[j] < arr1[i] && j < len) j++;
while (arr3[k] < arr1[i] && k < len) k++;
...
while (arrN[counterN] < arr1[i] && counterN < len) counterN++;
if (arr1[i] == arr2[j] && arr2[j] == arr3[k] && ... && arr1[i] == arrN[counterN]) {
toReturn.add(arr1[i]);
}
}
return toReturn;
}
This may be solved in O(M * N) with M being the length of arrays.
Let's see what happens for N = 2, this would be a sorted-list intersection problem, which has a classic merge-like solution running in O(l1 + l2) time. (l1 = length of first array, l2 = length of second array). (Find out more about Merge Algorithms.)
Now, let's re-iterate the algorithm N times in an inductive matter. (e.g. i-th time we will have the i-th array, and the intersection result of previous step). This would result in an overall O(M * N) algorithm.
You may also observe that this worst case upper-bound is the best achievable, since all the numbers must be taken into account for any valid algorithm. So, no deterministic algorithm with a tighter upper-bound may be founded.
Okay - maybe a bit naive here, but I think the clue is that the arrays are in ascending order. My java is rusty, but here is some pseduocode. I haven't tested it, so it's probably not perfect, but it should be a fast way to do this:
I = 1
J = 1
K = 1
While I <= Array1Count and J <= Array2Count and K <= Array3Count
If Array1(I) = Array2(J)
If Array1(I) = Array3(K)
=== Found Match
I++
J++
K++
else
if Array1(I) < Array3(K)
I++
end if
end if
else
If Array1(I) < Array2(J)
I++
else
if Array2(J) < Array3(K)
J++
else
K++
end if
end if
end if
Wend
This is Option Base 1 - you'd have to recode to do option base 0 (like java and other languages have)
I think another approach is to do similar thing to what we do in Mergesort: walk through all the arrays at the same time, getting identical numbers. This would take advantage of the fact that the arrays are in sorted order, and would use no additional space other than the output array. If you just need to print the common numbers, no extra space is used.
public static List<Integer> commonNumbers(int[] arrA, int[] arrB, int[] arrC) {
int[] idx = {0, 0, 0};
while (idxA<arrA.length && idxB<arrB.length && idxC<arrC.length) {
if ( arrA[idx[0]]==arrB[idx[1]] && arrB[idx[1]]==arrC[idx[2]] ) {
// Same number
System.out.print("Common number %d\n", arrA[idx[0]]);
for (int i=0;i<3;i++)
idx[i]++;
} else {
// Increase the index of the lowest number
int idxLowest = 0; int nLowest = arrA[idx[0]];
if (arrB[idx[1]] < nLowest) {
idxLowest = 1;
nLowest = arrB[idx[1]];
}
if (arrC[idx[2]] < nLowest) {
idxLowest = 2;
}
idx[idxLowest]++;
}
}
}
To make this more general you may want to take an arrays of arrays of ints, this will let you make the code more pretty. The array indeces must be stored in an array, otherwise it is hard to code the "increment the index that points to the lowest number" code.
public static List<Integer> getCommon(List<List<Integer>> list){
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
int c=0;
for (List<Integer> is : list) {
c++;
for (int i : is) {
if(map.containsKey(i)){
map.put(i, map.get(i)+1);
}else{
map.put(i, 1);
}
}
}
List<Integer>toReturn = new LinkedList<Integer>();
for(int key:map.keySet())
{
int count = map.get(key);
if(count==c)toReturn.add(key);
}
return toReturn;
}
Your solution is acceptable, but it uses NxM space. You can do it with O(N) space (where N is the number of arrays), or in O(1) space.
Solution #1 (By Luigi Mendoza)
Assuming there are many small arrays (M << N), this can be useful, resulting in O(M*N*Log M) time, and constant space (excluding the output list).
Solution #2
Scan the arrays in ascending order, maintaining a min-heap of size N, containing the latest visited values (and indices) of the arrays. Whenever the heap contains N copies of the same value, add the value to the output collection. Otherwise, remove the min value and advance with the corresponding list.
The time complexity of this solution is O(M*N*Log N)

Modifying the greatest elements of an array without changing their position?

I'm trying to figure out how to modify the n greatest elements of an array without modifying their position. For example, suppose I have an array of ints {5, 2, 3, 4, 8, 9, 1, 3};
I want to add 1 to the two greatest elements, making the array {5, 2, 3, 4, 9, 10, 1, 3}.
All of the methods I can think of to go about doing this end up feeling clunky and unintuitive when I try to implement them, signaling to me that I'm not thinking about it correctly. For example, I could use a TreeMap with the values of the array as keys and their indices as values to find the greatest values, modify them, and then throw them back into the array, but then I would have have to implement my own Comparator to sort the TreeMap in reverse order(unless there's an easier way I'm not aware of?). I was also considering copying the contents of the array into a list, iterating through n times, each time finding the greatest element and its index, putting the modified greatest element back into the array at that index, removing the element from the list, and repeat, but that feels sloppy and inefficient to me.
Any suggestions as to how to approach this type of problem?
The simplest thing would be to scan your array, and store the indices of the n highest values. Increment the values of those elements.
This is going to be O(n) performance, and I don't think any fancier methods can beat that.
edit to add: you can sort the array in place in O(n) at best, in which case you can get the n highest values very quickly, but the requirement is to not change position of the elements, so you'd have to start with a copy of the array if you wanted to do that (or preserve ordering information so you could put everything back afterward).
You might be over engineering the solution to this problem: scan the array, from beginning to end, and mark the two largest elements. Return to the two greatest elements and add 1 to it. The solution shouldn't be longer than 10 lines.
Loop over the array and keep track of the indices and values of the two largest items
a. Initialize the tracker with -1 for an index and MIN_INT for a value or the first two values of the array
b. At each step of the loop compare the current value against the two tracker values and update if necessary
Increment the two items
Any algorithm you choose should be O(n) for this. Sorting and n passes are way overkill.
Find the nth largest element (call it K) using techniques here and here (can be done in linear time), then go through the array modifying all elements >= K.
i would do something like this
int[] indices = new int[2];
int[] maximas = new int[] { 0, 0 };
int[] data = new int[] { 3, 4, 5, 1, 9 };
for (int i = 0; i < 5; ++i)
{
if (data[i] > maximas[1])
{
maximas[0] = maximas[1];
maximas[1] = data[i];
indices[0] = indices[1];
indices[1] = i;
}
else if (data[i] > maximas[0])
{
maximas[0] = data[i];
indices[0] = i;
}
}
didn't test it, but I think it should work :)
I have tought a bit about this but I cannot achieve more than worstcase:
O( n + (m-n) * n ) : (m > n)
best case:
O(m) : (m <= n)
where m = number of values, n = number of greatest value to search
This is the implementation in C#, but you can easily adapt to java:
int n = 3;
List<int> values = new List<int> {1,1,1,8,7,6,5};
List<int> greatestIndexes = new List<int>();
for (int i = 0; i < values.Count; i++) {
if (greatestIndexes.Count < n)
{
greatestIndexes.Add(i);
}
else {
int minIndex = -1, minValue = int.MaxValue;
for (int j = 0; j < n; j++)
{
if (values[greatestIndexes[j]] < values[i]) {
if (minValue > values[greatestIndexes[j]])
{
minValue = values[greatestIndexes[j]];
minIndex = j;
}
}
}
if (minIndex != -1)
{
greatestIndexes.RemoveAt(minIndex);
greatestIndexes.Add(i);
}
}
}
foreach (var i in greatestIndexes) {
Console.WriteLine(values[i]);
}
Output:
8
7
6

Categories

Resources