Question: Given an array numbers = {2, 7, 8, 5, 1, 6, 3, 9, 4}. Check the below conditions, both the conditions should be satisfied.
a[i] > a[i-1] or if first element a[i] > a[i+1]
a[i] > a[i+1] or if last element a[lastelement] > a[lastelement - 1]
Therefore:
1st Iteration - 8, 6, 9 are peak values. Remove the smallest ele. Remove 6. New arr {2, 7, 8, 5, 1, 3, 9, 4}. Output Arr - {6}
2nd Iteration - 8, 9 are peak values. Remove the smallest ele. Remove 8. New arr {2, 7, 5, 1, 3, 9, 4}. Output Arr - {6, 8}
3rd Iteration - 7, 9 are peak values. Remove the smallest ele. Remove 7. New arr {2, 5, 1, 3, 9, 4}. Output Arr - {6, 7, 8}
4th Iteration - 5, 9 are peak values. Remove the smallest ele. Remove 5. New arr {2, 1, 3, 9, 4}. Output Arr - {6, 7, 8, 5}
5th Iteration - 2, 9 are peak values. Remove the smallest ele. Remove 2. New arr {1, 3, 9, 4}. Output Arr - {6, 7, 8, 5, 2}
6th Iteration - 9 are peak values. Remove the smallest ele. Remove 9. New arr {1, 3, 4}. Output Arr - {6, 7, 8, 5, 2, 9}
7th Iteration - 4 are peak values. Remove the smallest ele. Remove 4. New arr {1, 3}. Output Arr - {6, 7, 8, 5, 2, 9, 4}
8th Iteration - 3 are peak values. Remove the smallest ele. Remove 3. New arr {1}. Output Arr - {6, 7, 8, 5, 2, 9, 4, 3}
9th Iteration - 1 are peak values. Remove the smallest ele. Remove 1. New arr {1}. Output Arr - {6, 7, 8, 5, 2, 9, 4, 3, 1}
Output: {6, 8, 7, 5, 2, 9, 4, 3, 1}
My solution is working but I am looking for optimized solution. Please let me know.
Here is my code:
public int[] findMinimumPeaks(int[] arr){
List<Integer> list1 = new ArrayList<Integer>(arr.length);
int[] output = new int[arr.length];
for(int i: arr)
list1.add(i);
for(int i =0; i<arr.length; i++){
int minIndex = minimumPeakElement(list1);
output[i] = list1.get(minIndex);
list1.remove(minIndex);
}
return output;
}
public int minimumPeakElement(List<Integer> list1){
int minIndex = 0, peakStart = Integer.MAX_VALUE, peakEnd = Integer.MAX_VALUE;
int peak = Integer.MAX_VALUE, minPeak = Integer.MAX_VALUE;
if(list1.size() >= 2){
if(list1.get(0) > list1.get(1)) peakStart = list1.get(0);
if(list1.get(list1.size() - 1) > list1.get(list1.size() - 2)) peakEnd = list1.get(list1.size() - 1);
if(peakStart < peakEnd){
minPeak = peakStart;
minIndex = 0;
}
else if(peakEnd < peakStart){
minPeak = peakEnd;
minIndex = list1.size() - 1;
}
}
for(int i=1; i<list1.size() - 1; i++){
if(list1.get(i) > list1.get(i + 1) && list1.get(i) > list1.get(i-1)) peak = list1.get(i);
if(peak < minPeak){
minPeak = peak;
minIndex = i;
}
}
return minIndex;
}
Here is an idea how to optimize asymptotic complexity.
Use single pass over elements of your initial array to split it into "up-down" "slopes" or "hills", i.e. subsequence of elements in ascending order, followed by subsequence in descending order.
Store these slopes in the following datastructure:
val slopes = MinPriorityQueue<Slope>()
class Slope(
var first: Int, // first element of the slope
var last: Int, // last element of the slope
var peak: Int, // max or peak element
var els: MaxPriorityQueue<Int>(), // all elements of the slope
var prev: Slope?, // link to the previous slope in the list or null if first
var next: Slope? // link to the next slope in the list or null if last
)
Slopes should be comparable by their peak value.
Now, having this data structure, you can poll the slope that has minimal peak value in O(log(N)). After you polled the slope, you should update the slope by removing it's peak element (i.e. poll els, then update first, last, peak), also, slope might become eligible to be merged with the previous or next slope:
Admittedly, this solution is not an easy one, having a lot of things to maintain and large number of corner cases. However, it's much better in terms of asymptotic complexity.
Initial data structure build: O(n log(n))
Polling elements while maintaining slopes: O(n log (n))
Overall complexity: O(n log(n))
Notes:
One of the corner cases, if array can have duplicate elements, then inner priority queue (els) becomes MaxPriorityQueue<Pair<Int,Int>>, i.e. you need to store the number of potentially duplicate elements along with the element value.
MinPriorityQueue and MaxPriorityQueue is an abstract heap-based data structure with min and max element at the head respectively. Can be implemented with PriorityQueue in java
Related
Multiple solutions available online for union of arrays, I came up with one of my own which is working fine but again it has significant time complexities (which I obviously don't know). So in order to use similar logic in a better way I am asking here. Any suggestion would be great!
Initially there are two arrayList with different sizes and numbers in it.
First step is to append both of them in a single List
Second step is to sort the new array using Collections.sort()
method.
Third is to use .remove() to remove the duplicates from it.
Below is the code
//initial two arrays
array1[0, 2, 3, 4, 5] and array2[0, 1, 2, 3, 5, 7, 8]
//for loop to append them in one arrayList and sort
for(k = 0; k< array1.size();k++){
array3.add(array1.get(k));
}
for(k = 0; k< array2.size();k++){
array3.add(array2.get(k));
}
Collections.sort(array3);
//Now removing the duplicates
for(k=0; k<array3.size();k++){
if(k != array3.size()-1){
if(Objects.equals(array3.get(k), array3.get(k + 1))){
array3.remove(k);
}
}
}
You can do this optimally via hash sets
int[] array1 = {0, 2, 3, 4, 5};
int[] array2 = {0, 1, 2, 3, 5, 7, 8};
HashSet<Integer> union = new HashSet<>();
for (int element : array1) {
union.add(element);
}
// Add all the elements of the second array to the HashSet
for (int element : array2) {
union.add(element);
}
this solution does not guarantee the order of the elements in the union set.
IntStream.distinct
You can use distinct() operation, which maintains a LinkedHashSet under the hood to guarantee uniqueness of elements and preserve their order, to obtain the union of the given arrays:
int[] array1 = {0, 2, 3, 4, 5};
int[] array2 = {0, 1, 2, 3, 5, 7, 8};
int[] union = IntStream
.concat(Arrays.stream(array1), Arrays.stream(array2))
.distinct().toArray();
System.out.println(Arrays.toString(union));
Output:
[0, 2, 3, 4, 5, 1, 7, 8]
I have a java problem at codewars.
In this kata, you will write a function that returns the positions and
the values of the "peaks" (or local maxima) of a numeric array.
For example, the array arr = [0, 1, 2, 5, 1, 0] has a peak at
position 3 with a value of 5 (since arr[3] equals 5).
The output will be returned as a Map<String,List>with two key-value pairs:"pos"and"peaks". If there is no peak in the given array, simply
return `{"pos" => [], "peaks" => []}.
Example: pickPeaks([3, 2, 3, 6, 4, 1, 2, 3, 2, 1, 2, 3]) should
return {pos: [3, 7], peaks: [6, 3]} (or equivalent in other
languages)
All input arrays will be valid integer arrays (although it could
still be empty), so you won't need to validate the input.
The first and last elements of the array will not be considered as
peaks (in the context of a mathematical function, we don't know what
is after and before and therefore, we don't know if it is a peak or
not).
Also, beware of plateaus! [1, 2, 2, 2, 1] has a peak while [1, 2, 2, 2, 3] and [1, 2, 2, 2, 2] do not. In case of a plateau-peak,
please only return the position and value of the beginning of the
plateau. For example: pickPeaks([1, 2, 2, 2, 1]) returns {pos: [1], peaks: [2]} (or equivalent in other languages)
Here is my answer:
public static Map<String, List<Integer>> getPeaks(int[] arr) {
HashMap<String, List<Integer>> stringListHashMap = new HashMap<>();
List<Integer> positions = new ArrayList<>();
List<Integer> values = new ArrayList<>();
values.add(arr[1]);
positions.add(1);
for (int i = 2; i < arr.length - 1; i++) {
if (values.get(values.size() - 1) < arr[i]) {
values.clear();
positions.clear();
values.add(arr[i]);
positions.add(i);
}
}
stringListHashMap.put("pos", positions);
stringListHashMap.put("peaks", values);
return stringListHashMap;
}
The above code works fine, but I don't pass the unit tests because of this ->
should support finding peaks expected:<{pos=[3, 7], peaks=[6, 3]}> but was:<{pos=[3], peaks=[6]}>
I have narrowed down the problem to this ->
Example: pickPeaks([3, 2, 3, 6, 4, 1, 2, 3, 2, 1, 2, 3]) should return {pos: [3, 7], peaks: [6, 3]} (or equivalent in other languages)
There is clearly only one peak which is 6 and its index 3. Then what is the person asking the question trying to say? I feel like I'm missing something.
The question is asking for local maxima, not global maxima. If a value is larger than its neighbours (and is not the first or last value), it's a peak, even if there is another value elsewhere that is even greater. Hence, with the input [3, 2, 3, 6, 4, 1, 2, 3, 2, 1, 2, 3], the eighth value (pos 7) is a peak, since the value 3 is greater than both the preceding neighbour (2) and following neighbour (2).
From what I understand, peak is surrounded by valley. So if you go up than down you have a peak, if you again go up and again down you have another peak. If you go up and than horizontal and than down, first position is peak, you just walk on plateau. It's like when you go mountain. You can climb 2 or 3 peaks in one trip.
Here is the solution:
public static Map<String, List<Integer>> getPeaks(int[] arr) {
Map<String, List<Integer>> result = new HashMap<>();
int peak = 0;
for (int i = 1; i < arr.length - 1; i++) {
if (arr[i-1] < arr[i]){
peak = i;
}
if(arr[i] > arr[i+1] && peak !=0) {
result.computeIfAbsent("pos", k -> new ArrayList<>()).add(peak);
result.computeIfAbsent("peaks", k -> new ArrayList<>()).add(arr[i]);
peak = 0;
}
}
return result;
}
I had to keep the current peak, as you can go horizontal and we need first position when you reach peak.
And I reset it when I go down.
So if arr[i-1] < arr[i] it means I reach a peak and if arr[i] > arr[i+1] && peak !=0 it means I went down.
Another mention, use Map as reference instead of HashMap. Same as you proceed for List.
Is there a way to find the initial sequence from its prefix sums and suffix sums?
Prefix sum at ith position is the sum of all elements from beginning to ith position.
Suffix sum at ith position is the sum of all elements from last to ith position in reverse order.
For an example, the combined (prefix sums and suffix sums) sequence is as follows:
{1, 3, 3, 5, 6, 6}
The initial sequence was: {1, 2, 3}
Prefix sums: {1, 3, 6}, Suffix sums: {6, 5, 3}
In combined: {1, 3, 3, 5, 6, 6}
May be in some cases there are multiple possibilities.
Prefix Sum:
original array : {1, 2, 3}
prefix sum array : {1, 1+2, 1+2+3}
Suffix Sum:
original array : {1, 2, 3}
suffix sum array : {3+2+1, 3+2, 3}
As per your question, the combined array seems to be sorted. Therefore
Let combined array be c[] = {1, 1+2, 3, 3+2, 1+2+3, 3+2+1} = {1, 3, 3, 5, 6, 6}
Now, finding the original sequence:
If original array has n elements then combined array will have 2*n elements
Split the array like array1 = {c[0], c[2], c[4]} and array2 = {c[1], c[3], c[5]}
array1 will now have prefix sum and array2 will have suffix sum
Now array1 is sufficient to find the original sequence (as combined array is sorted
as per your question). Therefore original array would be {c[0], c[2]-c[0], c[4]-c[2]}
int length = combined_array.length/2;
int []prefix_breakup = new int[length];
int []original = new int[length];
for(int i=0; i<length ; i++){
if( i%2 == 0 ){
prefix_breakup[i] = combined_array[i];
}
}
original[0] = prefix_breakup[0];
for(int i=1; i<length ; i++){
original[i] = prefix_breakup[i] - prefix_breakup[i-1];
}
For example, if I have an array a= {1, 2, 6, 10}, it should print all combinations of these 4 numbers, there should be 4! total combinations. An array of 5 integers will have a total of 5! combinations. (Different from previous versions because my number of parameters have to stay same. I am not allowed to put more than 3 paramrters in.
array a= {1, 2, 6, 10}
{1, 2, 10, 6}
{1, 6, 2, 10}
{1, 6, 10, 2}
.
.
.
{10, 6, 2, 1}
I am trying to solve this process using Recursion, any idea how? this is the code i have for now. Can anyone who has any idea whats going on please help me?
static void permutations (int a[], int n, int p){
if (p==n-1)
return ;
for (int i=p; i<n; i++){
int b[]=new int [n];
b[p]=a[i];
for (int j=0; j<i; j++)
b[j]=a[j];
for (int k =i+1; k<n; k++)
b[k]=a[k];
System.out.println(Arrays.toString(b));
return permutations(b, n, p+1);
}
}
best way to solve your problem to use Permutations concept in Algebra it's very useful way to get all possible combinations of a set.
you should also have knowledge in possibilities to solve this problem:
in this set {1, 2, 6, 10} element 1 has a k-Permutations which is 3
and this Permutations is : {2, 1, 6, 10},{6, 2, 1, 10},{10, 2, 6, 1}.
also element 2 has k-Permutations which is 2
2 Permutations is : {1, 6, 2, 10},{1, 10, 6, 2}.
element 6 has a k-Permutations which is 1
6 Permutations is : {1, 2, 10, 6}.
finally the total possible Permutations for all elements in set : 3 * 2 * 1 = 6.
simple algorithm to print all possible Permutations:
int[] num = {1,2,6,10};
int[] a = num.clone();
ArrayList<String> combs = new ArrayList<String>();
int temp;
for(int i=0; i < num.length-1; i++){
for(int j=i+1; j < num.length; j++){
temp = a[i];
a[i] = a[j];
a[j] = temp;
String obj = Arrays.toString(a);
if(!combs.contains(obj)){
combs.add(obj);
}
a = num.clone();
}
}
System.out.println("All possible order Combinations:");
for(String obj : combs){
System.out.println(obj);
}
output:
All possible order Combinations:
[2, 1, 6, 10]
[6, 2, 1, 10]
[10, 2, 6, 1]
[1, 6, 2, 10]
[1, 10, 6, 2]
[1, 2, 10, 6]
hope this would help.
I have a sorted array of type int. I want get the first index whose value is greater than a target in O(1), in java.
eg: int arr[]= {1,4,7,9,15,30}
target= 10
my function should return 4,index of 15.
In order to be able to find the index of a value that has a specific property (ex: is greater than a target) through an array, you must traverse the array implementing search algorithms.
Therefore O(1) is not possible to achieve.
If the array is sorted, as you present it in your example, you are able to achieve what you want in O(log(n)) by implementing binary search algorithm. You may also use the implementation in java.util.Arrays.
If the array is not sorted, you must go through all the elements of the array in a worst case scenario using linear search algorithm with an O(n) complexity.
If you prepare an indices array (or map) like this.
int[] a = {1,4,7,9,15,30};
// prepare indices array
int[] indices = new int[a[a.length - 1] + 1];
for (int i = 0, j = 0, aLength = a.length; i < aLength; ++i)
while (j <= a[i])
indices[j++] = i;
System.out.println(Arrays.toString(indices));
// -> [0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
// get the first index whose value is greater than a target in O(1)
System.out.println(indices[10]); // -> 4 (index of 15)
You can get the index value by indices[target] in O(1).