This problem is a celebrity on Leetcode - just like 2Sum. Because it builds fundamental knowledge of dynamic programming that is useful in a whole lot of other problems. A general approach toward solving algorithmic problems is to try and arrive at a brute force, unoptimised solution. The next step is to think how you can optimize it. Now, optimization techniques are dependent on the type of algorithm technique you have used. Since we use dynamic programming here we use A. memoisation OR B. tabulation. Because any one of the two is fine, one can chose the most readable one. I personally always stick with memoisation with a recursive solution - but there have been times when I have used tabulation.
Why DP here?
The problem requires us to
For conceptual understanding, take a look at the recursive tree below. Each node represents a recursive function call, the yellow letters denote the options available at that call. Suppose our input is str = "abc"
. As any recursive function requires a base case, the base case here is satisfied whenever the current permutation (that we are building in each function call) reaches the length of the input.
As you might have noticed by now, the algorithm needs to you make choices and then undo those choices when required. Below if a pseudocode of a backtracking algorithm:
We have worked with strings
in the above example, but the are no different than working with arrays.
Code:
C++
We are using vector<bool> used
which is same size of input (vector<int> nums
). This is so that we remember if any element is a valid option to use or not (see the yellow character in the string example above).
Big O Analysis
The time complexity here is O(N!)
as it would search for all possible outcomes, and the time increases exponentially with respect to the input size.
The space complexity is O(N!)
as well, the result vector will contain N! strings/arrays for all input strings/arrays N, where len(N) > 1
.