package com.freetymekiyan.algorithms.level.medium; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array. * <p> * Formally the function should: * Return true if there exists i, j, k * such that arr[i] < arr[j] < arr[k] given 0 ≤ i < j < k ≤ n-1 else return false. * Your algorithm should run in O(n) time complexity and O(1) space complexity. * <p> * Examples: * Given [1, 2, 3, 4, 5], * return true. * <p> * Given [5, 4, 3, 2, 1], * return false. * <p> * Company Tags: Facebook * Similar Problems: (M) Longest Increasing Subsequence */ public class IncreasingTripletSubsequence { private IncreasingTripletSubsequence i; /** * DP. * Similar to find two minimum values. * The only difference is we don't update second min when first min is found. * Otherwise n2 can be before n1, which is wrong. * So for each number n in nums: * | If n <= n1, update n1, that is the minimum. * | Else if n <= n2, update n2, that is the minimum after n1. * | Else, we find the third value, return true. * Return false if third value is not found. * Think it like we are filling three spaces. * The first space is the minimum. * When the first space is found, try to fill the second space. * If both are filled, when third space is filled, return true. */ public boolean increasingTriplet(int[] nums) { int n1 = Integer.MAX_VALUE; int n2 = Integer.MAX_VALUE; for (int n : nums) { if (n <= n1) { // Why <= ? Make sure arr[i] < arr[j] < arr[k]. n1 = n; } else if (n <= n2) { // n1 < n <= n2, since arr[i] < arr[j] < arr[k]. n2 = n; } else { return true; } } return false; } @Before public void setUp() { i = new IncreasingTripletSubsequence(); } @Test public void testExamples() { int[] input = {1, 2, 3, 4, 5}; Assert.assertTrue(i.increasingTriplet(input)); input = new int[]{5, 4, 3, 2, 1}; Assert.assertFalse(i.increasingTriplet(input)); } @After public void tearDown() { i = null; } }