i think the backtracking solution with decision tree is more intuitive. For each recursion call, you can store the number that has already added to the Answer list into the HashSet, and for each recursion call you can skip the number that already in the HashSet function permute(nums: number[]): number[][] { const result = [] const dfs = (set: Set, pm: number[]): void => { if (pm.length === nums.length) { result.push([...pm]) return } for (let i = 0; i < nums.length; i++) { if (set.has(nums[i])) { continue } pm.push(nums[i]) set.add(nums[i]) dfs(set, pm) pm.pop() set.delete(nums[i]) } } dfs(new Set(), []) return result }
I don't think I could've thought of this solution, the one I came up with was the backtracking one, so it's nice to learn a new approach at least! List copy is O(n) and slicing+inserting is also O(n). The backtracking approach only has a list copy (assuming appending and popping are O(1)). def permute(self, nums: List[int]) -> List[List[int]]: if not nums: return [] permutations = [] # To store all our permutations curr_indices = set() # To keep track of the indices used so far curr_path = [] # What stores the current permutation (temporarily) size = len(nums) # Store it for readability def dfs(idx): if len(curr_indices) == size: # Base case when we find a permutation permutations.append(curr_path.copy()) # Add a copy of the permutation return for i in range(size): # Go over every remaining possible addition if i not in curr_indices: # Constraint - do not explore already explored index curr_indices.add(i) # Keep track of added indices curr_path.append(nums[i]) # Store the updated permutation dfs((i + 1) % size) # Explore this new branch curr_indices.remove(i) # Once explored, remove it so this set can be used again curr_path.pop() # Same reasoning as removing from the set dfs(0) return permutations
This is a way better explanation than the old video. I went months with this problem unsolved because I just couldn't understand, but this explanation helped me tremendously. Thanks!
Swapping indices method for this question is probably more clear and you should also review Longest Palindromic Substring question. Solutions in the other questions are quite optimal. Thanks a lot!
java version of this solution: class Solution { public List permute(int[] nums) { if (nums.length == 0) { return List.of(List.of()); } List res = new ArrayList(); List perms = permute(Arrays.copyOfRange(nums, 1, nums.length)); for (List p : perms) { for (int i = 0; i < p.size() + 1; i++) { List pCopy = new ArrayList(p); pCopy.add(i, nums[0]); res.add(pCopy); } } return res; } }
Is it possible for you to have some sort of poll or something where we could ask for a video solution of a leetcode problem which you haven't already solved. Because there are quite a few problems which don't have a proper solution on UA-cam and God knows when they will appear as POTD.
Ok, this one's really the first problem in neetcode150 that is actually VERY easy to understand the goal but I personally find it extremely hard to implement
@@NeetCodeIO I tried to understand it but it's really bad when debugging or writing down on paper. Really hard to understand. I found this solution: def permute(self, nums: List[int]) -> List[List[int]]: res = [] def backtrack(arr): if len(arr) == len(nums): res.append(arr.copy()) return
for i in range(len(nums)): if nums[i] in arr: continue arr.append(nums[i]) backtrack(arr) arr.pop()
backtrack([]) return res This I got. If no one supports me and everyone thinks your solution is good. Then I'm wrong.
@@m_jdm357 Actually, I understood the concept better through this video and the solution that is being implemented is similar to yours. ua-cam.com/video/gFm1lEfnzUQ/v-deo.html
i think the backtracking solution with decision tree is more intuitive. For each recursion call, you can store the number that has already added to the Answer list into the HashSet, and for each recursion call you can skip the number that already in the HashSet
function permute(nums: number[]): number[][] {
const result = []
const dfs = (set: Set, pm: number[]): void => {
if (pm.length === nums.length) {
result.push([...pm])
return
}
for (let i = 0; i < nums.length; i++) {
if (set.has(nums[i])) {
continue
}
pm.push(nums[i])
set.add(nums[i])
dfs(set, pm)
pm.pop()
set.delete(nums[i])
}
}
dfs(new Set(), [])
return result
}
yeah I thought the same. he's also slicing and inserting in the middle of arrays which are O(n) operations.
I don't think I could've thought of this solution, the one I came up with was the backtracking one, so it's nice to learn a new approach at least!
List copy is O(n) and slicing+inserting is also O(n). The backtracking approach only has a list copy (assuming appending and popping are O(1)).
def permute(self, nums: List[int]) -> List[List[int]]:
if not nums:
return []
permutations = [] # To store all our permutations
curr_indices = set() # To keep track of the indices used so far
curr_path = [] # What stores the current permutation (temporarily)
size = len(nums) # Store it for readability
def dfs(idx):
if len(curr_indices) == size: # Base case when we find a permutation
permutations.append(curr_path.copy()) # Add a copy of the permutation
return
for i in range(size): # Go over every remaining possible addition
if i not in curr_indices: # Constraint - do not explore already explored index
curr_indices.add(i) # Keep track of added indices
curr_path.append(nums[i]) # Store the updated permutation
dfs((i + 1) % size) # Explore this new branch
curr_indices.remove(i) # Once explored, remove it so this set can be used again
curr_path.pop() # Same reasoning as removing from the set
dfs(0)
return permutations
I came up with this direction as well, neetcode is usually great but I like this alternative solution better.
Easy to understand (imo) DFS solution:
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
def dfs(perm):
if len(perm) == len(nums):
res.append(perm[:])
return
for i in range(len(nums)):
if nums[i] in perm:
continue
perm.append(nums[i])
dfs(perm)
perm.pop()
dfs([])
return res
This is a way better explanation than the old video. I went months with this problem unsolved because I just couldn't understand, but this explanation helped me tremendously. Thanks!
I live in Russia, a new day has not yet begun, and you are already solving a new problem)
i feel like a time traveler
me too, i didn't look at the published timestamp, everything is kinda strange tho.
Swapping indices method for this question is probably more clear and you should also review Longest Palindromic Substring question. Solutions in the other questions are quite optimal.
Thanks a lot!
Thank you neetcode for again working on this problem :)
@NeetcodeIO PLS add a functionality on your site to not show the topics for the questions. want to do them in order without knowing the topic. thanks
java version of this solution:
class Solution {
public List permute(int[] nums) {
if (nums.length == 0) {
return List.of(List.of());
}
List res = new ArrayList();
List perms = permute(Arrays.copyOfRange(nums, 1, nums.length));
for (List p : perms) {
for (int i = 0; i < p.size() + 1; i++) {
List pCopy = new ArrayList(p);
pCopy.add(i, nums[0]);
res.add(pCopy);
}
}
return res;
}
}
You Make it easy, Thank you
Morning Neetcode!
hey also do video for cherry pickup 1 and bst to sorted DLL
I wouldn't recommend this way of doing it since slicing and inserting are O(n) operations
I actually just solved the problem yesterday lmao
Morning
Is it possible for you to have some sort of poll or something where we could ask for a video solution of a leetcode problem which you haven't already solved. Because there are quite a few problems which don't have a proper solution on UA-cam and God knows when they will appear as POTD.
I guess thats what his site is for.
Ok, this one's really the first problem in neetcode150 that is actually VERY easy to understand the goal but I personally find it extremely hard to implement
Now Solve 31 Next Permutation
This solution doesn't help much. It doesn't provide any useful insights for similar problems, and I'm not sure why it was explained to us.
The worst solution I've seen.
anything specific about it that you did not like?
@@NeetCodeIO I tried to understand it but it's really bad when debugging or writing down on paper. Really hard to understand. I found this solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
def backtrack(arr):
if len(arr) == len(nums):
res.append(arr.copy())
return
for i in range(len(nums)):
if nums[i] in arr:
continue
arr.append(nums[i])
backtrack(arr)
arr.pop()
backtrack([])
return res
This I got. If no one supports me and everyone thinks your solution is good. Then I'm wrong.
@@m_jdm357 Actually, I understood the concept better through this video and the solution that is being implemented is similar to yours.
ua-cam.com/video/gFm1lEfnzUQ/v-deo.html
you could be a bit nicer :D