2

Anyone can convert this in the Java functional style (lambda):

public int findSecondMin(int arr[]) {

    int min = Integer.MAX_VALUE, secondMin = Integer.MAX_VALUE;
    for (int i = 0; i < arr.length; i++) {
        if (min > arr[i]) {
            secondMin = min;
            min = arr[i];
        } else if (secondMin > arr[i]) {
            secondMin = arr[i];
        }
    }
    return secondMin;
}

I tried by applying the filter over this but it is not working.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
Sandeep Tiwari
  • 2,042
  • 3
  • 24
  • 47

5 Answers5

4

Using an IntStream, you can easily sort it and skip the first element:

public int findSecondMin(int[] arr)
{
    return IntStream.of(arr).sorted().skip(1).findFirst().orElse(Integer.MAX_VALUE);
}

But of course, you don't have to use streams. java.util.Arrays has a nice sort method, and then you can just take the second element:

public int findSecondMin(int[] arr)
{
    Arrays.sort(arr);
    return arr.length < 2 ? Integer.MAX_VALUE : arr[1];
}

To avoid sorting the whole array, we can take your approach and adapt it into a custom reduction on the stream:

public int findSecondMin(int[] arr)
{
    return IntStream.of(arr).boxed().reduce(
        new int[] {Integer.MAX_VALUE, Integer.MAX_VALUE},
        (mins, i) -> {
            return new int[] {Math.min(i, mins[0]), Math.min(Math.max(i, mins[0]), mins[1])};
        }, (mins1, mins2) -> {
            int[] lesser = mins1[0] < mins2[0] ? mins1 : mins2;
            int[] larger = mins1[0] < mins2[0] ? mins2 : mins1;
            return new int[] {lesser[0], Math.min(lesser[1], larger[0])};
        }
    )[1];
}

Compared to a for loop based implementation, it might be harder to read, but can work in parallel.

Malte Hartwig
  • 4,477
  • 2
  • 14
  • 30
  • 1
    It becomes O(nlogn) if you sort the array. – zhh Aug 06 '18 at 10:11
  • Yes, that's a downside. But I dont't really see how a stream based solution could achieve the goal without relying on outside state or ending up exactly like the original for loop with a custom reduce object. These sorting-based solutions are very readable, at least. – Malte Hartwig Aug 06 '18 at 10:13
  • @Malte Hartwig could you please explain time complexity as well, As per me sorting is o(n^2)? – Sandeep Tiwari Aug 06 '18 at 10:16
  • The second solution changes the order of the caller's `arr` as a side effect. –  Aug 06 '18 at 10:17
  • 1
    @SandeepTiwari the complexity depends on the chosen sorting algorithm. Basic approaches like bubble sort indeed tend to n2, but the Java functions will rely on more advanced techniques. From the JavaDoc of `Arrays.sort()`: "Implementation note: The sorting algorithm is a Dual-Pivot Quicksort". You could check the JavaDoc for the stream sorting and then check those algorithms. – Malte Hartwig Aug 06 '18 at 10:19
  • @saka1029 also true. It could be fixed by copying the array or wrappin it in a list first. The sorting approach certainly is not as lightweight as looking for the minimums yourself. I'll see if I can up with a custom reduction. – Malte Hartwig Aug 06 '18 at 10:20
  • 4
    [How to find the kth largest element in an unsorted array of length n in O(n)?](https://stackoverflow.com/q/251781/2711488) – Holger Aug 06 '18 at 11:24
  • @Holger oh darn :) one of the suggested links says build a min heap (`PriorityQueue`) and pop twice... I thought about that initially and now I feel like an idiot :) thx for the link! – Eugene Aug 06 '18 at 11:51
  • "but can work in parallel" since reduce uses the initial or previous value as comparison I have no idea how it would manage that. – Sylwester Aug 06 '18 at 12:11
  • @Sylwester that's why I used the `reduce` method with three parameters. That one defines the identity to be used for each subset and a combiner to merge the results of those subsets. Also, all the arrays used are not modified, preventing side effects when running in parallel. – Malte Hartwig Aug 06 '18 at 12:13
  • That is impressive. 1+ :) – Sylwester Aug 06 '18 at 12:20
3

There is a way even without sorting working in the case all the numbers are unique. Filter out the minimum value and ask again for another one resulting in the 2nd lowest value.

int firstMin = Arrays.stream(arr).min().getAsInt();
int secondMin = Arrays.stream(arr).filter(i -> i != firstMin).min().getAsInt();

System.out.println(firstMin);  // prints 2
System.out.println(secondMin); // prints 3

Edit: There is another way using the TreeSet implementation which stores already sorted values. Remove the lowest one and ask for the first element again - it results in the 2nd lowest element:

SortedSet<Integer> sortedSet = Arrays.stream(arr)
                                     .boxed()
                                     .collect(Collectors
                                         .toCollection(TreeSet::new));
sortedSet.remove(sortedSet.first());
int secondMin = sortedSet.first();

System.out.println(secondMin); // prints 3
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
0

here you find the Example

    List<Integer> numbers = Arrays.asList(10, 2, 3, 4, 5, 6);
            numbers.sort(Comparator.naturalOrder());
            System.out.println(numbers.get(1));
Faiz Akram
  • 559
  • 4
  • 10
0

EDIT: As mentioned in comments - below solution will NOT work for parallel processing!

To avoid sorting we can use reduce function. And reduce to "pair like structure" (in the example imitated by array):

public class Test {

    private static final int SECOND_LOWEST = 1;
    private static final int LOWEST = 0;
    @Test
    public void test() {
        Integer[] arr = {0, 3, 4, 5, 2, 3, 5, 6, 7, 8, 1};
        List<Integer> list = Arrays.asList(arr);
        int[] identity = {Integer.MAX_VALUE, Integer.MAX_VALUE};
        int[] result = list.stream()
                       .reduce(identity, (acc, elem) -> calculate(acc, elem), (acc1, acc2) -> acc1);

       System.out.println(Arrays.toString(result));
    }

    private int[] calculate(int[] acc, Integer elem) {
        if (acc[LOWEST] > elem) {
            int prevLowest = acc[LOWEST];
            acc[LOWEST] = elem;
            acc[SECOND_LOWEST] = prevLowest;
        } else if (acc[SECOND_LOWEST] > elem) {
                acc[SECOND_LOWEST] = elem;            
    }
    return acc;
}
piradian
  • 414
  • 7
  • 19
  • `(acc1, acc2) -> acc1`... just add `parallel` and see the result you will get – Eugene Aug 06 '18 at 10:52
  • I didn't think with paralelisation in mind. But you right, the complete solution should take this into consideration. – piradian Aug 06 '18 at 11:15
  • Since you are modifying the temporary array, you should use `collect`, which is specifically designed to handle so so-called *Mutable Reduction*. – Holger Aug 06 '18 at 11:17
0
public int min(){
  int a[] ={2,5,1,3};
  int min, secondMin = a[0];
  for(int i=0;i<a.length;i++){
        if(min>a[i]){
             secondMin =min;
             min= a[i];
           }
      }
  return secondMin;
}

i got the second min from above code segment...try this.....

malith vitha
  • 473
  • 4
  • 4