Start learning free

LESSON 290 OF 410 · BACKTRACKING

Generate Valley Permutations in Java with Time Complexity Analysis

Practice O(n!) Read the full explanation

Given a positive integer n, return all the valley permutations of length n.

A valley permutation is defined as a permutation that is a concatenation of two parts: a monotonically decreasing sequence and then a monotonically increasing sequence.

E.g. valley permutations follow this format: [p[0] > p[1] > p[2] > ... > p[k] < p[k+1] < p[k+2] < ... < p[n-1]].


Example:

Input: n = 4

Output:[
    [1, 2, 3, 4],
    [2, 1, 3, 4],
    [3, 1, 2, 4],
    [3, 2, 1, 4],
    [4, 1, 2, 3],
    [4, 2, 1, 3],
    [4, 3, 1, 2],
    [4, 3, 2, 1]
]

Explanation:
Permutations such as [1, 4, 2, 3] are not valleys because 1 < 4 > 2 < 3

Notes: n <= 10


STEP 1 OF 14
    Ctrl + Enter to check

    JAVA · BACKTRACKING

    Generate Valley Permutations in Java, explained

    Understanding the Problem

    The core challenge of this problem is to generate all permutations of length n that follow the valley pattern. This pattern is characterized by a sequence that first decreases and then increases. This problem is significant in various applications such as sorting algorithms, combinatorial optimization, and sequence analysis.

    Potential pitfalls include generating permutations that do not follow the valley pattern or missing some valid permutations. Misconceptions might arise from misunderstanding the valley pattern definition.

    Approach

    To solve this problem, we need to generate all permutations of the sequence and then filter out those that do not follow the valley pattern. A naive solution would involve generating all permutations and checking each one, but this is not optimal due to the factorial time complexity of generating permutations.

    An optimized approach involves generating permutations in a way that inherently respects the valley pattern. This can be achieved by dividing the sequence into two parts: a decreasing part and an increasing part, and then combining them.

    Algorithm

    1. Generate all permutations of the sequence [1, 2, ..., n].

    2. For each permutation, check if it follows the valley pattern.

    3. If it does, add it to the result list.

    Code Implementation

    import java.util.ArrayList;
    import java.util.List;
    
    public class ValleyPermutations {
        // Function to generate all valley permutations of length n
        public static List<List<Integer>> generateValleyPermutations(int n) {
            List<List<Integer>> result = new ArrayList<>();
            List<Integer> current = new ArrayList<>();
            boolean[] used = new boolean[n + 1];
            backtrack(result, current, used, n);
            return result;
        }
    
        // Helper function for backtracking
        private static void backtrack(List<List<Integer>> result, List<Integer> current, boolean[] used, int n) {
            if (current.size() == n) {
                if (isValley(current)) {
                    result.add(new ArrayList<>(current));
                }
                return;
            }
            for (int i = 1; i <= n; i++) {
                if (!used[i]) {
                    used[i] = true;
                    current.add(i);
                    backtrack(result, current, used, n);
                    current.remove(current.size() - 1);
                    used[i] = false;
                }
            }
        }
    
        // Function to check if a permutation is a valley
        private static boolean isValley(List<Integer> permutation) {
            int n = permutation.size();
            int i = 0;
            // Find the peak
            while (i < n - 1 && permutation.get(i) < permutation.get(i + 1)) {
                i++;
            }
            // Check if the rest is decreasing
            while (i < n - 1 && permutation.get(i) > permutation.get(i + 1)) {
                i++;
            }
            return i == n - 1;
        }
    
        // Main function to test the implementation
        public static void main(String[] args) {
            int n = 4;
            List<List<Integer>> valleyPermutations = generateValleyPermutations(n);
            for (List<Integer> permutation : valleyPermutations) {
                System.out.println(permutation);
            }
        }
    }
    

    Complexity Analysis

    The time complexity of generating all permutations is O(n!), and checking each permutation for the valley pattern is O(n). Therefore, the overall time complexity is O(n * n!). The space complexity is O(n) for the recursion stack and the current permutation list.

    Edge Cases

    Edge cases include:

    • n = 0: The output should be an empty list.
    • n = 1: The output should be [[1]].
    • Handling duplicate values in the sequence (though not applicable here as the sequence is from 1 to n).

    Testing

    To test the solution comprehensively, include a variety of test cases:

    • Simple cases like n = 1 and n = 2.
    • Edge cases like n = 0.
    • Complex cases like n = 10.

    Use testing frameworks like JUnit for automated testing.

    Thinking and Problem-Solving Tips

    When approaching such problems, break down the problem into smaller parts and solve each part step-by-step. Practice solving similar problems and study different algorithms to improve problem-solving skills.

    Conclusion

    Understanding and solving valley permutation problems helps in developing combinatorial and algorithmic thinking. Practice and exploration of different approaches are key to mastering such problems.

    Additional Resources

    Keep going with JavaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free