Backtracking: Permutations - Leetcode 46 - Python

แชร์
ฝัง
  • เผยแพร่เมื่อ 22 ส.ค. 2024

ความคิดเห็น • 261

  • @NeetCode
    @NeetCode  3 ปีที่แล้ว +20

    I rerecorded this solution and made it much better, please watch this instead: th-cam.com/video/FZe0UqISmUw/w-d-xo.html

    • @abdullahtahan
      @abdullahtahan 5 หลายเดือนก่อน

      please add monthly subscription so i can try it before paying full year

  • @reggiehurley1479
    @reggiehurley1479 ปีที่แล้ว +232

    usually neetcode has the best solutions/explanations but i gotta say this is the first time ive seen him have the most confusing one lol. Maybe there's a reason he did it this way that will be beneficial for us down the line but it seems to be the worst solution for permutations ive seen. maybe because of that i should understand it lol. i love neetcode btw - best youtuber by far.

    • @hbhavsi
      @hbhavsi 11 หลายเดือนก่อน +10

      I agree with your analysis. I was too confused and disappointed in this solution. The editorial solution on LC is neat and easy to understand.

    • @c_hlee
      @c_hlee 10 หลายเดือนก่อน +5

      yeah.. this neetcode solution was destroying me until i looked at the leetcode editorial that made perfect sense

    • @yuqian822
      @yuqian822 10 หลายเดือนก่อน +3

      I agree with you! I was doubting myself lol this solution doesn't work for me. (I love this guy!)

    • @imang3719
      @imang3719 9 หลายเดือนก่อน +2

      I felt the same and I was like it's probably only me, glad I'm not the only one, lol. Still love neetcode for all the videos and explanations

    • @Bullimicporkupine
      @Bullimicporkupine 7 หลายเดือนก่อน +5

      i think the idea is sometimes you have to do a bit of the heavy-lifting, cant expect NC to spoonfeed us everything

  • @jz1607
    @jz1607 6 หลายเดือนก่อน +29

    Every time I feel stupid and not able to solve a leetcode question, I get to your video for the explanation and the moment I realize the video has 200k+ views I understand that I"m not stupid, just a regular human like hundreds of thousands others.

    • @dnc077
      @dnc077 3 หลายเดือนก่อน

      I'm feeling stupid too - I feel incompetent. I thought this would be a walk in the park.

    • @adama7752
      @adama7752 3 หลายเดือนก่อน +5

      @@dnc077 it's okay bro, it's just training your brain for pattern recognition. It requires effort + time !

  • @Grawlix99
    @Grawlix99 ปีที่แล้ว +56

    We can avoid popping elements and passing in the remaining list by simply swapping elements. Anyways, an alternative backtracking approach for those who are interested (very short, code, too!):
    def permute(self, nums: List[int]) -> List[List[int]]:
    res = []
    def backtrack(i):
    if i >= len(nums):
    res.append(nums[:])
    for j in range(i, len(nums)):
    nums[i], nums[j] = nums[j], nums[i]
    backtrack(i+1)
    nums[i], nums[j] = nums[j], nums[i]
    backtrack(0)
    return res

    • @m3hdim3hdi
      @m3hdim3hdi ปีที่แล้ว

      so beautiful idea, where did you get the inspiration?

    • @rishabsaini8347
      @rishabsaini8347 11 หลายเดือนก่อน +1

      I also originally solved it by swapping and undoing the swapping, instead of pop and push into the array.

    • @rishabsaini8347
      @rishabsaini8347 11 หลายเดือนก่อน +2

      @@m3hdim3hdi Permutation is just number of ways to put stuff say in a row or on a circle, so swapping is analogous to changing the order in the row.

    • @juggles5474
      @juggles5474 11 หลายเดือนก่อน +3

      Thank you for this beautifully intuitive solution

    • @samuraijosh1595
      @samuraijosh1595 11 หลายเดือนก่อน +1

      in haskell:
      import Data.List
      permute :: Eq a => [a] -> [[a]]
      permute [] = [[]]
      permute xs = [x : ys | x

  • @TheElementFive
    @TheElementFive 2 ปีที่แล้ว +24

    The nuances of the recursive logic in these problems are so hard to visualize ahh!

  • @sniff4643
    @sniff4643 3 ปีที่แล้ว +66

    lmao this video was so good I watched the first few minutes of it and was able to code the problem myself. I then coded another leetcode medium backtracking by myself based on the intuition i got from this video all by myself with 86% time complexity. And these are the first 2 times I have ever done a back tracking problem. you are good asf dude.

    • @Shingorani
      @Shingorani 3 ปีที่แล้ว +34

      i think you're good asf for being able to do that based off a few mins of this vid

    • @fatropolis6909
      @fatropolis6909 2 ปีที่แล้ว +14

      This guy lying thru his fokin teeth

    • @TheElementFive
      @TheElementFive 2 ปีที่แล้ว +1

      riiiight

    • @demaxl732
      @demaxl732 7 หลายเดือนก่อน

      @@fatropolis6909How do you know?

  • @siddharthgupta848
    @siddharthgupta848 2 ปีที่แล้ว +12

    Hi, actually we can also use this template -
    class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    result = []
    n = len(nums)
    def backtrack(perm):
    if len(perm) == len(nums):
    result.append(perm.copy())
    return
    for i in range(n):
    if nums[i] in perm:
    continue
    perm.append(nums[i])
    backtrack(perm)
    perm.pop()
    backtrack([])
    return result
    This is similar to how we solve combination problem , we have to do some slight modification .

    • @himanshu6489
      @himanshu6489 2 ปีที่แล้ว

      what's the use of perm here? where we're using it?

    • @siddharthgupta848
      @siddharthgupta848 2 ปีที่แล้ว

      @@himanshu6489 perm here is used to store individual permutation

    • @jorgecabiedes1877
      @jorgecabiedes1877 2 ปีที่แล้ว +3

      Not as efficient since checking if nums[i] in perm is linear worst case, you could maybe use a set instead to make it constant

  • @rahulprasad8243
    @rahulprasad8243 2 ปีที่แล้ว +23

    How did you map the decision tree to the recursion logic?

  • @Ron-op8es
    @Ron-op8es 3 ปีที่แล้ว +15

    thank u ive been searching forever, this is the only video on this problem with this much effort involved

    • @NeetCode
      @NeetCode  3 ปีที่แล้ว +2

      Thanks, I'm glad it was helpful =)

  • @jsarvesh
    @jsarvesh 3 ปีที่แล้ว +20

    We can use the index of nums array itself and compute the permutations instead of popping the
    elements from the beginning and appending it later
    def permute(self, nums: List[int]) -> List[List[int]]:
    """ Angle of Attack
    - use recursive method
    - base case when one element
    - recursive call to compute permutation except that element

    """
    result = list()
    # base case -- least valid input
    if len(nums) == 1:
    return [nums]

    for idx in range(len(nums)):
    # compute the permutation for ith element
    current_nums = nums[:idx] + nums[idx+1:]
    # recursive case
    perms = self.permute(current_nums)
    # permutation generated above don't have the
    # ith element, so append it
    for perm in perms:
    perm.append(nums[idx])

    # update the overall results with all (multiple) permutations
    result.extend(perms)
    #return all permutations
    return result

  • @likkiii07
    @likkiii07 ปีที่แล้ว +7

    Hey, I have used the same tree but a slightly diff approach where u call recursion if that element doesn't exist in perm array
    def permute(self, nums: List[int]) -> List[List[int]]:
    res = []

    def backtrack(perm):
    # base case
    if len(perm) == len(nums):
    res.append(perm)
    return
    for num in nums:
    if num not in perm:
    backtrack(perm + [num])

    backtrack([])
    return res

    • @jason1666
      @jason1666 ปีที่แล้ว +1

      it's beautiful

    • @samuraijosh1595
      @samuraijosh1595 11 หลายเดือนก่อน

      @@jason1666most elegant solution:
      in haskell:
      import Data.List
      permute :: Eq a => [a] -> [[a]]
      permute [] = [[]]
      permute xs = [x : ys | x

  • @danielsun716
    @danielsun716 ปีที่แล้ว +6

    My thought is initially the same with Neetcode. I draw a decision tree from an empty list. So I write this code for a straight forward understanding.
    def permute(self, nums: List[int]) -> List[List[int]]:
    res = []
    def backtrack(nums, perm):
    if not nums:
    res.append(perm)
    return
    for i in range(len(nums)):
    backtrack(nums[: i] + nums[i + 1:], perm + [nums[i]])
    backtrack(nums, [])
    return res

    • @danny65769
      @danny65769 ปีที่แล้ว +1

      I had the same solution as you. I think you need to do perm.copy() when you append to res on line 5?

    • @danielsun716
      @danielsun716 ปีที่แล้ว +1

      @@danny65769 Yes, you can. But you dont have to. perm is not a global variable, so we can just append perm, not perm.copy()

  • @JimmyCheng
    @JimmyCheng 3 ปีที่แล้ว +26

    awesome contents as always. I found your channel to be the best Leetcode problem solution explanation channel on TH-cam!

  • @bilalmunawar6058
    @bilalmunawar6058 2 ปีที่แล้ว +19

    Thank you! Backtracking builds potential candidates to solution and abandons a candidate if it no longer leads to a valid solution - this is also called pruning the recursion tree. Can anyone please explain in which instance do we abandon a candidate here? I just want to understand why it falls in backtracking category

    • @H_Blackburn
      @H_Blackburn 2 ปีที่แล้ว +14

      We abandon a candidate when we pop(0)

  • @msnhao
    @msnhao 2 ปีที่แล้ว +7

    I think you're doing duplicate work here. For example, if nums = [1, 2, 3, 4, 5, 6]
    Then you would call: permute([1, 2, 3, 4, 5]) + append 6 on everything returned
    and: permute([1, 2, 3, 4, 6]) + append 5 on everything returned
    However, that means you'll be computing permute([1, 2, 3, 4]) twice, which is inefficient.
    You can make this more efficient by starting from the bottom up.
    i.e. [1] -> [1, 2], [2, 1] - > [1, 2, 3], [1, 3, 2], [3, 1, 2], [2, 1, 3], [2, 3, 1], [3, 2, 1]
    Here, for each permutation of the length n, you create n+1 new lists of length n+1 where you insert the new number into every possible position. This way, you only calculate each sub-permutation once

  • @almasmirzakhmetov8590
    @almasmirzakhmetov8590 ปีที่แล้ว +3

    it seems I fully understand your idea but when it comes to writing code it requires from me a lot thinking, struggling

    • @bree9895
      @bree9895 ปีที่แล้ว +1

      us bestie

  • @ravikant-hi8mz
    @ravikant-hi8mz 3 ปีที่แล้ว +16

    But this code does not work on leetcode. It gives errors

  • @sreenivaskrishna7351
    @sreenivaskrishna7351 13 วันที่ผ่านมา

    Thank you for alll you do @NeetCode
    slightly more intuitive for me
    our remaining choices keep shrinking
    class Solution(object):
    def permute(self, nums):
    """
    :type nums: List[int]
    :rtype: List[List[int]]
    """
    result = []
    def generate_permutations(permutation, remaining):
    if not remaining:
    result.append(permutation)
    return
    for i in range(len(remaining)):
    generate_permutations(permutation + [remaining[i]], remaining[:i] + remaining[(i + 1):])
    generate_permutations([], nums)
    return result

  • @dzmitryk9658
    @dzmitryk9658 3 ปีที่แล้ว +14

    Keep doing this! It's really good!

  • @Karim-nq1be
    @Karim-nq1be ปีที่แล้ว +2

    I really like your explanation, but this solution seems a bit too convoluted for such a simple problem. I get that it's expected in some interviews, still I find it quite silly.

  • @poorpanda9033
    @poorpanda9033 11 หลายเดือนก่อน +1

    Thank you so much man !! Please don't delete this videos

  • @bhushanmahajan2150
    @bhushanmahajan2150 2 ปีที่แล้ว +14

    Could you please tell the time and space complexity of this solution?

    • @spencerlong4393
      @spencerlong4393 2 ปีที่แล้ว +1

      O(n*n!) for time. The way I thought about it is that there are n! permutations for an array of length n. For each permutation, we need to make n calls to get to the leaves (permutations), so O(n * n!). As for space, I think it's O(n!). We have to store n! permutations.

  • @shreshthkaushik-hu8bz
    @shreshthkaushik-hu8bz 10 วันที่ผ่านมา

    I wrote it differently. Might or might not be more useful
    def permute(self, nums: List[int]) -> List[List[int]]:
    # Create a list to store the output and a set to keep track of all the taken numbers
    output, taken = [], set()
    # Create a function to take every permutation of unique numbers
    def permutations_generator(permutation: list):
    # Base case if the length of permutation is equal to number of elements in nums
    if len(permutation) == len(nums):
    output.append(permutation.copy())
    return
    # Go through each number in nums and add that into permutation list if its unique
    for number in nums:
    if number not in taken:
    permutation.append(number)
    taken.add(number)
    # Run permutations_generator after adding one number
    permutations_generator(permutation=permutation)
    # After the permutations_generator has completed, remove the added numbers for further processing
    permutation.pop()
    taken.remove(number)
    permutations_generator(permutation=[])
    return output

  • @walterchang1046
    @walterchang1046 ปีที่แล้ว +3

    Why is that local variable : "result" won't initialize when "perm = self.permute(nums)" been executed?
    Isn't it better to avoid setting a local variable when dealing with a recursion function?

  • @prasantheits55
    @prasantheits55 ปีที่แล้ว +2

    Is line 14 logically correct?? What does it mean??
    for perm in perms:
    perm.append(n)

  • @yushi7964
    @yushi7964 2 ปีที่แล้ว +4

    What is the time complexity?

  • @kingrudong9761
    @kingrudong9761 4 หลายเดือนก่อน

    Note that all possible permutations of one array with distinct integers is """pop one from the array, and find all possible permutations from the exist""" . For example, for array like [1, 2, 3], first pop one from it, like 1, then 1 is the first number of the permutation we are finding. Now arrray [2, 3] remains. Continue to find until there's only one number that has not been processed.(Constrain: nums.length >= 1) Add it after the permutation and append to the result list.
    def permute(self, nums: List[int]) -> List[List[int]]:
    res = []
    cur_permu = []
    def dfs(cur_list):
    if len(cur_list) == 1:
    res.append(cur_permu.copy() + cur_list)
    return
    for index, num in enumerate(cur_list):
    cur_permu.append(num)
    dfs(cur_list[:index] + cur_list[index + 1:])
    cur_permu.pop()

    dfs(nums)
    return res
    this solution is really efficient.

  • @vishweshganapathy8189
    @vishweshganapathy8189 10 หลายเดือนก่อน

    def permute(self, nums):
    resultList = []
    self.backtrack(resultList, [], nums)
    return resultList

    def backtrack(self, resultList, tempList, nums):
    if len(tempList) == len(nums):
    resultList.append(list(tempList))
    return

    for number in nums:
    if number in tempList:
    continue
    tempList.append(number)
    self.backtrack(resultList, tempList, nums)
    tempList.pop()

  • @Adnarimel
    @Adnarimel 2 ปีที่แล้ว +2

    I'm crying -- multiple comments begging for the time / space complexity and still no answer... i am also begging

    • @djplt1240
      @djplt1240 2 ปีที่แล้ว

      I believe time is O(n!) (maybe O( n! ^2)) because each recursion is looping roughly n^2 then (n-1)^2... (e.g an array of length for is looping roughly 4*3*2*1). Space (Extra not including the result) is O(n), because it's the maximum recursion depth.

  • @danielsun716
    @danielsun716 ปีที่แล้ว +6

    Three different ways to solve including Neetcode's solution. And I think this problem's three solutions inspired me so much, so sharing with you guys.
    def permute(self, nums: List[int]) -> List[List[int]]:
    if len(nums) == 1:
    return [nums[:]]
    res = []
    for i in range(len(nums)):
    n = nums.pop(0)
    perms = self.permute(nums)
    for perm in perms:
    perm.append(n)
    res.extend(perms)
    nums.append(n)
    return res
    # res = []
    # def backtrack(perm):
    # if len(perm) == len(nums):
    # res.append(perm.copy())
    # return
    # for i in range(len(nums)):
    # if nums[i] in perm:
    # continue
    # perm.append(nums[i])
    # backtrack(perm)
    # perm.pop()
    # backtrack([])
    # return res
    # res = []
    # def backtrack(nums, perm):
    # if not nums:
    # res.append(perm)
    # return
    # for i in range(len(nums)):
    # backtrack(nums[: i] + nums[i + 1:], perm + [nums[i]])
    # backtrack(nums, [])
    # return res

    • @DhruvOberoi
      @DhruvOberoi ปีที่แล้ว +1

      You can optimise your second solution's time complexity by maintaining a set in addition to the perm array that will make "if nums[i] in perms" O(1) constant time as opposed to O(n). The tradeoff is with the space complexity as that will now be slightly less optimal given you have to maintain a hashset that could take O(n) space.

    • @danielsun716
      @danielsun716 ปีที่แล้ว

      @@DhruvOberoi yup

    • @danny65769
      @danny65769 ปีที่แล้ว +1

      I think the 3rd solution is easiest to understand.

  • @sidazhong2019
    @sidazhong2019 2 ปีที่แล้ว +6

    we can use the similar approach like problem 17, the only difference is string and list. list needs deep copy. just a little bit slower than average.
    17:
    rs = []
    def loop(k,v):
    if k == len(digits):
    rs.append(v)
    return
    for vv in hashmap[digits[k]]:
    loop(k+1,v+vv)
    if digits:
    loop(0,"")
    return rs
    46
    rs = []
    def loop(k,v):
    if k==len(nums):
    rs.append(v)
    return
    for vv in nums:
    tmp=v[:]
    if vv not in tmp:
    tmp.append(vv)
    loop(k+1,tmp)
    loop(0,[])
    return rs

  • @markomekjavic
    @markomekjavic 2 ปีที่แล้ว +8

    Really good video - makes concepts so much easier to understand! But I do have a question, why do you return [nums.copy()] instead of. just [nums] as a base case?

    • @meghrajgupta4560
      @meghrajgupta4560 2 ปีที่แล้ว +8

      To not get caught up in the call by reference problem. By default lists are passed on by reference rather than value.

  • @user-rn6tl4ww8o
    @user-rn6tl4ww8o 2 หลายเดือนก่อน

    class Solution:
    def permute(self, nums):
    res =[]
    perm= []
    def dfs():
    if len(perm) == len(nums):
    res.append(perm.copy())
    return
    for n in nums:
    if n not in perm:
    perm.append(n)
    dfs()
    perm.pop()
    dfs()
    return res

  • @aalindsingh927
    @aalindsingh927 2 ปีที่แล้ว +6

    Can anyone explain how using a slicing operator (nums[:]) made our solution faster compared to nums.copy()

    • @australianpanda2713
      @australianpanda2713 2 ปีที่แล้ว +2

      it doesnt. leetcode is just flaky

    • @keshavsanthanam3767
      @keshavsanthanam3767 ปีที่แล้ว

      [:] is a deep copy, not a shallow copy. not sure how it helps tho...

  • @doctormonk6638
    @doctormonk6638 3 ปีที่แล้ว +7

    Code does not work

  • @harishsn4866
    @harishsn4866 2 ปีที่แล้ว +7

    Can you please let us know the time complexity of this? It's still gonna be O(∑k=1N​P(N,k)) right? Since we are calling the recursive function for every element? It would be helpful if you can elaborate in the comments section and pin it.

    • @josecarlosdelcastillo4398
      @josecarlosdelcastillo4398 ปีที่แล้ว

      +1 to this

    • @MasterAraid
      @MasterAraid ปีที่แล้ว

      my guess is that since we are doing O(n) work per recursive call, and since the algorithm is exponential (two recursive calls with constant difference), the total runtime is O(n2^n)

    • @denysivanov3364
      @denysivanov3364 ปีที่แล้ว

      @@MasterAraid N factorial N!

  • @unnhao
    @unnhao 12 วันที่ผ่านมา

    I think use `splice` is more easy to track and understand, and Permutations || also can use the same code to add some condition to solve.
    /**
    * @param {number[]} nums
    * @return {number[][]}
    */
    var permute = function(nums) {
    let res = [];
    if (nums.length === 1) {
    return [nums.slice()];
    }
    for(let i = 0; i < nums.length; i++) {
    let n = nums.splice(i, 1)[0]
    let perms = permute(nums);
    for(let perm of perms) {
    perm.push(n);
    }
    res = [...res, ...perms];
    nums.splice(i, 0, n)
    }
    return res;
    };

  • @leo6d985
    @leo6d985 หลายเดือนก่อน

    It would have been so good for you to explain the deviation from the traditional bactracking approach. This is very hard to understand, very counter intuitive. Still, love your work.

  • @udittalks949
    @udittalks949 6 หลายเดือนก่อน

    You know what I about this guy is the ease which he explains the problems I also saw his system design course for beginners ..just wonde

  • @amirilifee
    @amirilifee 11 หลายเดือนก่อน +1

    I still dont get it how u come up with these brilliant ideas?! When i see your solution, i wonder why i dont come with this idea if its so easy? haha
    Thanks brother!!

    • @samuraijosh1595
      @samuraijosh1595 11 หลายเดือนก่อน

      in haskell:
      import Data.List
      permute :: Eq a => [a] -> [[a]]
      permute [] = [[]]
      permute xs = [x : ys | x

  • @GESAM121
    @GESAM121 2 ปีที่แล้ว +5

    Great video, can you add in the bookmark for starting explaining the solution like you have in other videos?

  • @Codenames560
    @Codenames560 2 ปีที่แล้ว +2

    thanks man, i had hard time understanding this problem but this video helped a lot!

  • @agnishwarbagchi4935
    @agnishwarbagchi4935 2 ปีที่แล้ว +1

    def permute(self, nums: List[int]) -> List[List[int]]:

    output = []

    def backtracking(res):
    if len(res) == len(nums):
    output.append(list(res))


    for i in nums:
    if i not in res:
    res.append(i)
    backtracking(res)
    res.pop()


    backtracking([])

    return output

    • @rasi9441
      @rasi9441 ปีที่แล้ว

      you should add return after output.append(list(res)), so that base can return from there itself rather than going again into the loop to exit.
      thanks

  • @letsgoooooo
    @letsgoooooo 7 หลายเดือนก่อน

    Much easier solution-
    class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    n = len(nums)
    ans = []
    used = set()
    def dfs(arr):
    if len(arr) == n:
    ans.append(arr.copy())
    return

    for num in nums:
    if num not in used:
    used.add(num)
    arr.append(num)
    dfs(arr)
    arr.pop()
    used.remove(num)
    dfs([])
    return ans

  • @softwareengineer8923
    @softwareengineer8923 ปีที่แล้ว +1

    your explanation and solution is pretty fluent.Thanks for a great video,

  • @shrimpo6416
    @shrimpo6416 3 ปีที่แล้ว +20

    NEET CODE INDEED! I wish I've watched your videos earlier. Such clean solution written in Python!

  • @aakashavril
    @aakashavril 2 หลายเดือนก่อน

    I like the solutions by neetcode but this one is particularly very confusing and does not come naturally. The following approach builds each permutation choosing one element at a time and further building up the solution.
    class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    res = []
    self.dfsPermute(res,nums,[])
    return res
    def dfsPermute(self,res,nums,curr):
    if len(curr)==len(nums):
    # base case when we found one permutation solution
    res.append(curr.copy())
    # go over each element add it to the list
    for n in nums:
    # check to avoid dulicate value in the arr
    if n in curr:
    continue
    else:
    # call recursively for each case
    curr.append(n)
    self.dfsPermute(res,nums,curr)
    #undo the last chosen element and go to the other decision branch tree
    curr.pop()

  • @user-zv3mr7bo1d
    @user-zv3mr7bo1d หลายเดือนก่อน

    Easier version, the way neetcode did it for combinations:
    class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    visit = set()
    res = []
    n = len(nums)
    def backtrack(permute, visit):
    if len(permute) == len(nums):
    res.append(permute.copy())
    return
    for i in range(len(nums)):
    if nums[i] not in visit:
    permute.append(nums[i])
    visit.add(nums[i])
    backtrack( permute, visit )
    visit.remove(nums[i])
    permute.pop()
    backtrack([], visit)
    return res

  • @amreshgiri
    @amreshgiri ปีที่แล้ว +2

    What would be the time complexity of this algorithm?

  • @vinitrinh
    @vinitrinh ปีที่แล้ว +1

    Whats the time and space complexity and how can we explain it?

  • @redye5858
    @redye5858 10 หลายเดือนก่อน +1

    Love everything you have done but this honestly should be a 25-min video

  • @kshitijg2979
    @kshitijg2979 2 ปีที่แล้ว +4

    Thanks

  • @shubhambindal7333
    @shubhambindal7333 8 หลายเดือนก่อน +1

    Hey @NeetCode would be a issue if we do the following:
    Its TC is still seems to same as n.n! and SC - n
    stack = []
    set_ = set()
    output = []
    def backTrack():
    if len(stack)==len(nums):
    output.append(list(stack))
    return
    for i in range(len(nums)):
    if nums[i] not in set_:
    stack.append(nums[i])
    set_.add(nums[i])
    backTrack()
    stack.pop()
    set_.remove(nums[i])
    backTrack()
    return output

  • @inderwool
    @inderwool ปีที่แล้ว

    Thanks! Never thought to think of it in terms of a decision tree.

  • @KarinaRodriguez-yv7mf
    @KarinaRodriguez-yv7mf 2 ปีที่แล้ว +2

    How would this look like in Java? I've been racking my brain on how to not append to sublists that have already been appended to

    • @TechOnScreen
      @TechOnScreen 2 ปีที่แล้ว

      in Java, you need to add it to the list instead

  • @AchyutSarmaB
    @AchyutSarmaB 11 หลายเดือนก่อน

    Here is a simpler solution that goes very well with the pen and paper method explained in the video to keep things consistent. Cheers!
    ```
    class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    if len(nums)==1:
    return [nums]
    result = []
    for i in range(len(nums)):
    remaining = [j for j in nums if j!=nums[i]]
    current_permutation = [nums[i]]
    self.dfs(remaining, current_permutation, result)
    return result
    def dfs(self, remaining, current_permutation, result):
    # base case
    if len(remaining)==1:
    current_permutation.extend(remaining)
    result.append(current_permutation.copy())
    return
    # take a decision for each remaining element
    for j in range(len(remaining)):
    new_remaining = remaining[:j]+remaining[j+1:]
    self.dfs(new_remaining, current_permutation+[remaining[j]], result)
    ```

  • @AyushSingh-yq4so
    @AyushSingh-yq4so 8 หลายเดือนก่อน +1

    Nice solution
    Can you please tell about space and time complexity
    Thanks

  • @hoyinli7462
    @hoyinli7462 3 ปีที่แล้ว

    your ans is super clear, much better than the leetcode official one. Liked

  • @J0RdN-w
    @J0RdN-w ปีที่แล้ว +1

    Such clean solution
    and i just come up with this solution
    class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    if len(nums)

  • @TechOnScreen
    @TechOnScreen ปีที่แล้ว +1

    Did not understand, can you explain in details pls

  • @bonafontciel
    @bonafontciel 2 ปีที่แล้ว +4

    I like your channel and appreciate the time you take. However this solution is too pythonic. Better to swap, backtrack, swap

  • @ashishm8850
    @ashishm8850 3 ปีที่แล้ว +5

    Very well explained. Thanks a lot!

    • @alwayssporty8102
      @alwayssporty8102 3 ปีที่แล้ว

      hey can u explain what the 10th line exactly does how does it gives all permutations of the remaining 2 digits??

    • @delta619
      @delta619 9 หลายเดือนก่อน

      @@alwayssporty8102
      for i in range(len(nums)):
      n = nums.pop(i)
      perms = self.permute(nums)
      for perm in perms:
      perm.append(n)
      result.extend(perms)
      nums.insert(i, n)
      you can do this instead
      it basically takes the digit out from the number and lets the permutation run on rest of the combination of digits.

  • @ogoubah
    @ogoubah 2 ปีที่แล้ว +2

    What's the time complexity?

  • @user-vh9vx7rq1i
    @user-vh9vx7rq1i 2 หลายเดือนก่อน

    Thank you Neetcode. Can you show the time complexity analysis for this solution?

  • @franciscosauceda2511
    @franciscosauceda2511 3 ปีที่แล้ว +10

    Hi, Thank you for making this video! I have one question though. Why do you need to make a copy of the base case ( nums[:] ) ?

    • @shuruizhao4112
      @shuruizhao4112 3 ปีที่แล้ว +9

      Say if for the base case, [nums] instead of [nums[:]] is returned, perms = self.permute(nums) essentially becomes perms = [nums] (note nums is a list), and the iterator perm in perms is now equivalent to nums. perm.append(n) modifies not only perm, but also nums which shares the reference of perm.
      To see the difference, you can do a print(perm) and print(nums), or print(perm==nums) after perm.append(n) in for perm in perms loop.

    • @abishekanbarasan5537
      @abishekanbarasan5537 3 ปีที่แล้ว +3

      Deep copy vs shallow copy

    • @simsim2159
      @simsim2159 3 ปีที่แล้ว +2

      @@abishekanbarasan5537 what is the difference?

  • @AlanSchooll
    @AlanSchooll 2 ปีที่แล้ว

    solution in c++
    class Solution
    {
    // vector array for result
    vector> result;

    // set to remember which element is already selected
    set st;
    void permutation(vector &nums, vector &res)
    {
    // if the size of res become size of num pushed res in result vector and array

    if (res.size() == nums.size())
    {
    result.push_back(res);
    return;
    }

    for (int i = 0; i < nums.size(); i++)
    {
    // check if the current number is not chosen

    if (st.find(nums[i]) == st.end())
    {
    // insert number in set to remember that the following number is already selected
    st.insert(nums[i]);

    // insert current number in res array
    res.push_back(nums[i]);

    // recursively call permutation to select another number
    permutation(nums, res);

    // on backtrackingremove the current selected number from selected because we are done with possible solution with that selected number
    st.erase(nums[i]);

    //also remove from res array
    res.pop_back();
    }
    }
    }
    public:
    vector> permute(vector &nums)
    {
    vector res;
    permutation(nums, res);
    return result;
    }
    };

  • @light_70
    @light_70 10 หลายเดือนก่อน

    I have watched this three times, this was complicated.

  • @amandasun6677
    @amandasun6677 ปีที่แล้ว +1

    What is the time and space complexity of this solution?

  • @thomasantony3381
    @thomasantony3381 25 วันที่ผ่านมา

    Bro Memory Limit Exceeded

  • @sujithameriga7348
    @sujithameriga7348 5 หลายเดือนก่อน

    Most beautiful code. I had to use a visualizer to fully understand it though.

    • @ballzi3122
      @ballzi3122 2 หลายเดือนก่อน

      what visualizer?

  • @daniyalkabir6527
    @daniyalkabir6527 2 ปีที่แล้ว +1

    Can we thank NeetCode enough?

    • @NeetCode
      @NeetCode  2 ปีที่แล้ว +1

      Happy to help :)

  • @adrienveidt8273
    @adrienveidt8273 3 ปีที่แล้ว +1

    why not just return [[nums[0]]] which also work and simpler rather than [nums[:]] ?

  • @stith_pragya
    @stith_pragya 6 หลายเดือนก่อน +1

    Thank You So Much for this wonderful video.......🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻

  • @Gribozhuy
    @Gribozhuy ปีที่แล้ว

    Simple java solution:
    class Solution {
    List result = new ArrayList();
    public List permute(int[] nums) {
    rec(nums, new HashSet(), new ArrayList());
    return result;
    }
    private void rec(int[] nums, Set used, List temp) {
    if (temp.size() == nums.length) {
    result.add(temp);
    }
    for (int i=0; i < nums.length; i++) {
    if (!used.contains(i)) {
    Set newUsed = new HashSet(used);
    newUsed.add(i);
    List newTemp = new ArrayList(temp);
    newTemp.add(nums[i]);
    rec(nums, newUsed, newTemp);
    }
    }
    }
    }

  • @aabhishek4911
    @aabhishek4911 2 ปีที่แล้ว +1

    can any one plz explain why we need to append n back to nums ? what does it achieve

  • @edwardteach2
    @edwardteach2 3 ปีที่แล้ว +4

    Did it without the use of pop(0)
    def permutations_num(nums):
    result = []
    if len(nums) == 1:
    return [nums[:]]
    for _ in range(len(nums)):
    n = nums[0]
    perms = permutations_num(nums[1:])
    for perm in perms:
    perm.append(n) # [2,3]+[1] and [3,2]+[1] individually
    result.extend(perms) # [2,3,1],[3,2,1] all together into the result
    return result
    print(permutations_num([1,2,3]))

    • @NeetCode
      @NeetCode  3 ปีที่แล้ว +1

      That's great, I like this one better!

    • @kai-chiehhuang3939
      @kai-chiehhuang3939 3 ปีที่แล้ว

      The first few lines of the outer for loop should be like this in order to work
      for i in range(len(nums)):
      n = nums[i]
      perms = permutations_num(nums[:i]+nums[i+1:])

    • @ssy13542
      @ssy13542 2 ปีที่แล้ว

      class Solution:
      def permute(self, nums: List[int]) -> List[List[int]]:
      result = []
      if len(nums) == 1:
      return [nums[:]]
      for i in range(len(nums)):
      n = nums[i]
      perms = self.permute(nums[:i]+nums[i+1:])
      for perm in perms:
      perm.append(n) # [2,3]+[1] and [3,2]+[1] individually
      result.extend(perms) # [2,3,1],[3,2,1] all together into the result
      return result

    • @hailei
      @hailei 2 ปีที่แล้ว

      @NeetCode the pop(0) has O(n) time complexity. This solution might be better.

    • @edwardteach2
      @edwardteach2 2 ปีที่แล้ว +1

      @@hailei In my interviews, I still resort to Neetcode's solution lol

  • @miyamotomusashi4556
    @miyamotomusashi4556 2 ปีที่แล้ว

    I wrote this:
    class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    """
    :type nums: List[int]
    :rtype: List[List[int]]
    """
    if len(nums) == 1:
    return [nums]
    elif len(nums) == 0:
    return [[]]
    result = []
    sub = self.permute(nums[1:])
    for arr in sub:
    for i in range(len(arr)+1):
    temp = arr.copy()
    temp.insert(i, nums[0])
    result.append(temp)
    return result
    It's almost self explanatory.

  • @badguy7432
    @badguy7432 4 หลายเดือนก่อน

    5:17 code only gives 1x of undo swap function and you can only access this function once you are done with the recusive calls and has printed the array result of one such permutation, how are you able to go back up more than one iterations above? That's what you need to explain

  • @MrLeyt1125
    @MrLeyt1125 5 หลายเดือนก่อน

    Its better to use next_permutation function from C++. Its easy to write it by yourself in any language. Backtrack solution is too heavy

  • @vinayak6330
    @vinayak6330 6 หลายเดือนก่อน

    Same underlying login but more understandable code? Any feedback is appreciated.
    def permute(self, nums: List[int]) -> List[List[int]]:

    res = []
    def dfs(cur, temp):
    if len(temp) == len(nums):
    res.append(temp.copy())
    return
    for i in range(len(cur)):
    temp.append(cur[i])
    dfs(cur[:i] + cur[i+1:], temp)
    temp.pop()
    dfs(nums, [])
    return res

  • @PippyPappyPatterson
    @PippyPappyPatterson ปีที่แล้ว

    I think building the permutation on the way down is way more intuitive than on the way back up.
    Please verify my complexity analysis at the bottom:
    ```python
    class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
    res = []
    def dfs(cur: list[int], nums: list[int]) -> None:
    if not nums:
    res.append(cur.copy())
    return
    for _ in range(len(nums)):
    cur.append(nums[-1])
    temp = nums.pop()
    dfs(cur, nums)
    nums.append(temp)
    cur.pop()
    nums = nums[1:] + nums[:1]
    dfs([], nums)
    return res
    # O(n! * n) O(n)
    ```

  • @pemessh
    @pemessh 2 ปีที่แล้ว +1

    Naive question :)
    Why do we need to return the copy of the nums arrray?
    Sorry I'm stupid.

    • @shaksham.22
      @shaksham.22 3 หลายเดือนก่อน

      In python, a list variable is just a pointer pointing to the memory location where the list is present
      so if you do list1=list2. both list1 and list2 will be same.
      so eg:-
      list1=[1,2,3,4,5]
      list2=list1
      list1.pop()
      print(list1)=======>[1,2,3,4]
      print(list2)=======>[1,2,3,4]
      in python id() will give you the memory location.
      so if you print(id(list1)) the value will be same as id list2
      on other hand copy will do a deepcopy of the list and make it a new list with different pointer.
      so when passing through return etc, if you try changing things in a return list it will also get changed in the original passed variable unless you copy it.

  • @AliHaider-bc7cl
    @AliHaider-bc7cl 4 หลายเดือนก่อน

    how dumb should i consider myself if i cant figure it out after 2+ weeks of python

  • @ishansharma6198
    @ishansharma6198 2 ปีที่แล้ว +1

    hey, thanks for the video, extremely informed, just wanted to understand why do we append the removed element to the end of the main array and not at the same position?

    • @shalombentenzingnamchyo9384
      @shalombentenzingnamchyo9384 2 ปีที่แล้ว +2

      Its because we are removing the first element every time. Had it been pop(i) then we would have to insert it at the same position. because we must remove every element at least once. Eg. 1,2,3 first call from this will be per(2,3)(we remove the first element then the list will be 2,3,1 and the second call from the loop will be per(3,1). After that the list will be 3,1,2 and per(1,2) will be called.

  • @howardlam6181
    @howardlam6181 ปีที่แล้ว

    no need to pop and appened if you just swap the elements and shift start position and swap them back afterwards.

  • @LeonC0704
    @LeonC0704 5 หลายเดือนก่อน

    what's the difference between the channels neetcode and needcodeIO???

  • @lucaswang8457
    @lucaswang8457 2 ปีที่แล้ว

    I just got asked this leetcode problem in my today's interview.
    And I failed. LOL.

    • @okolichidiebere4456
      @okolichidiebere4456 2 ปีที่แล้ว

      Everyone here has failed many times.. Actually, many * many times.

  • @lampham7874
    @lampham7874 ปีที่แล้ว

    The explanation is beautiful, thanks.

  • @orangethemeow
    @orangethemeow 2 ปีที่แล้ว +1

    In the picture explanation, should the second subtree be [3, 1]? We popped the first element from [2, 3, 1]

  • @sakshamgupta5726
    @sakshamgupta5726 ปีที่แล้ว +1

    How to do it lexicographically without using internal function for permutations (from itertools)?

    • @infiniteloop5449
      @infiniteloop5449 ปีที่แล้ว

      This solution doesn't use itertools....

  • @SuperAce780
    @SuperAce780 6 หลายเดือนก่อน

    this was an awesome solution! thanks

  • @vinayakhaunsnur1327
    @vinayakhaunsnur1327 ปีที่แล้ว

    tq very much i learnt more of dsa by your problems

  • @unnhao
    @unnhao 13 วันที่ผ่านมา

    This solution use chart is easy to know, but code... is so hard

  • @s8x.
    @s8x. 10 หลายเดือนก่อน

    I’m having trouble understanding the code. I get the drawing but coding it is so much harder

  • @user-kw5hm7fq5m
    @user-kw5hm7fq5m 2 หลายเดือนก่อน

    Why u made a copy of nums in the base case ?
    Please help

  • @-SiddharthaChappidi
    @-SiddharthaChappidi 2 หลายเดือนก่อน

    Hi , whats the time complexity of the solution?

  • @rayhanmuktader1064
    @rayhanmuktader1064 5 หลายเดือนก่อน

    I don't understand why we have to append "n" back at the end of nums. Can anyone explain?

  • @bossmusa9075
    @bossmusa9075 ปีที่แล้ว

    i have spend 15 minutes. I was close but not enought in coding.

  • @nguyen-dev
    @nguyen-dev 2 ปีที่แล้ว +1

    If using mutable collection, time complexity is exactly the space complexity for output: O(n * n!).
    The list instance is created "only" at the base case. Then the result of base case is always reused and mutated with O(1) time complexity to add single value.
    Using immutable collection, I am not sure how to compute it but it will be much slower.

  • @dragonemperor5775
    @dragonemperor5775 3 ปีที่แล้ว +1

    What would be the time complexity for this algo.?