Drawing diagrams helps. Here's your linked list:
Copy[ ]
|
v
[ ]
|
V
[ ]
|
V
None
Each arrow leading from a box represents the next attribute of that node.
Here are the three variables a, b, and c:
Copy [ ] <-- a
|
v
[ ] <-- b
|
V
[ ] <-- c
|
V
None
Each of these variables also points to a particular node.
If you say b.next = None, the next attribute of the node referenced by b is modified, like this:
Copy [ ] <-- a
|
v
None <-- [ ] <-- b
[ ] <-- c
|
V
None
This modifies the structure of the list. If you just set b itself to a different value, though, this is what happens:
Copy [ ] <-- a
|
v
None <-- [ ] b --> None
[ ] <-- c
|
V
None
You changed b, but the node that b used to point to stays right where it was. Note that this is similar to how the c node continued to exist even after you set b.next = None.
https://m.youtube.com/watch?v=lvO88XxNAzs
I love Python, itโs my first language and the language that got me into FAANG (interviews and projects).
Itโs not my day to day language (now TypeScript) but I definitely think itโs the best for interviews and getting started which is why I used it in this video.
Included a ton of Python tips, as well as programming and software engineering knowledge. Give a watch if you want to improve on these and problem solving skills too ๐ซก
Videos
Drawing diagrams helps. Here's your linked list:
Copy[ ]
|
v
[ ]
|
V
[ ]
|
V
None
Each arrow leading from a box represents the next attribute of that node.
Here are the three variables a, b, and c:
Copy [ ] <-- a
|
v
[ ] <-- b
|
V
[ ] <-- c
|
V
None
Each of these variables also points to a particular node.
If you say b.next = None, the next attribute of the node referenced by b is modified, like this:
Copy [ ] <-- a
|
v
None <-- [ ] <-- b
[ ] <-- c
|
V
None
This modifies the structure of the list. If you just set b itself to a different value, though, this is what happens:
Copy [ ] <-- a
|
v
None <-- [ ] b --> None
[ ] <-- c
|
V
None
You changed b, but the node that b used to point to stays right where it was. Note that this is similar to how the c node continued to exist even after you set b.next = None.
Python doesn't have double pointers e.g. **x
Copyb.next = c
print(a) # a is 1 -> 2 -> 3
b.next = None
E.g. in above, it doesn't mean c is None
When a.next is b, if you change a.next.next you are effectively changing b.next
But if you change a.next to None, it will not set b to None
Edit:
Also when you set b = None but a.next still points ListNode(2)
Turns out the solution to this is to use: nums[:] = nums[newIndex+1:len(nums)] + nums[0:newIndex+1].
Doing nums = nums[newIndex+1:len(nums)] + nums[0:newIndex+1] simply changes the reference, while nums[:] changes the values of the list.
You can use
sudo service network-manager restart
The short answer to this is that, Python is a pass-by-object-reference language, not pass-by-reference as implied in the question. It means that:
resultandresult_tailare two variables that happen to point at the same value- Mutation / Changing of the underlying value (
result_tail.next = ListNode(1)) will affect the value shown byresult - However, assigning / pointing the variable
result_tailto another value will NOT affect the value ofresult result_tail = result_tail.nextis assigning the next node of the node that is currently assigned by the variable
The following is an visualization of the values that are assigned to the variables (r = result, rt = result_tail):
result = ListNode(0)
#r
#0 -> None
result_tail = result
#r
#0 -> None
#rt
result_tail.next = ListNode(1)
#r
#0 -> 1 -> None
#rt
result_tail = result_tail.next
#r
#0 -> 1 -> None
# rt
result_tail.next = ListNode(2)
#r
#0 -> 1 -> 2 -> None
# rt
result_tail = result_tail.next
#r
#0 -> 1 -> 2 -> None
# rt
References for additional reading:
- An article explaining the Python pass-by-object reference style in detail https://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/
- An answer explaining Python's pass-by-object reference style https://stackoverflow.com/a/33066581/12295149
- Question asking on Python's object reference style Understanding Python's call-by-object style of passing function arguments
For those reading this in the future: I wanted to debug linked list problems on a local environment so here is what I did.
- Modified the Leetcode code for ListNode by including the dunder "repr" method. This is for when you want to print a ListNode to see what its value and next node(s).
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def __repr__(self):
return "ListNode(val=" + str(self.val) + ", next={" + str(self.next) + "})"
- Next, I made a recursive function that makes a nested ListNode when you pass in a list. This is so you can test your methods by passing in lists (instead of having to manually make a confusing looking ListNode yourself.
def list_to_LL(arr):
if len(arr) < 1:
return None
if len(arr) == 1:
return ListNode(arr[0])
return ListNode(arr[0], next=list_to_LL(arr[1:]))
- Here is an example that tests my answer for the "reverseList" problem:
def reverseList(head: ListNode) -> ListNode:
prev = None
while head:
next_node = head.next
head.next = prev
prev = head
head = next_node
return prev
# test cases
t1 = list_to_LL([1, 2, 3, 4, 5]) #ListNode(val=1, next={ListNode(val=2, next={ListNode(val=3, next={ListNode(val=4, next={ListNode(val=5, next={None})})})})})
t2 = list_to_LL([1, 2]) #ListNode(val=1, next={ListNode(val=2, next={None})})
t3 = list_to_LL([])
# answers
print(reverseList(t1))
print(reverseList(t2))
print(reverseList(t3))