Reorder linked list in python - python

I tried to solve this problem. However, I have got time limit exceed.
Anyone can solve this problem without time limitation exceeds?
Here is the question.
You are given the head of a singly linked-list. The list can be represented as:
L0 → L1 → … → Ln - 1 → Ln
Reorder the list to be on the following form:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
You may not modify the values in the list's nodes. Only nodes themselves may be changed.
Here is my implementation. However, time limit exceeds.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reorderList(self, head: Optional[ListNode]) -> None:
"""
Do not return anything, modify head in-place instead.
"""
temp=head
temp2=None
if temp.next is None:
pass
elif temp.next.next is None:
pass
else:
while temp.next:
temp2=temp
while temp2.next:
prev=temp2
temp2=temp2.next
temp2.next=temp.next
temp.next=temp2
prev.next=None
if temp2.next.next is None:
break
if temp2.next.next.next is None:
break
temp=temp.next.next

There is a "Discuss" section on LeetCode, where you could find some solutions and explanations.
One possible solution from there:
class Solution:
def reorderList(self, head: ListNode) -> None:
if not head:
return head
# find mid point
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# reverse the second half in-place
# slow.next: the start point of reverse
head2 = None
curr = slow.next
slow.next = None
while curr:
next = curr.next
curr.next = head2
head2 = curr
curr = next
# merge in-place
first, second = head, head2
while second:
first.next, first = second, first.next
second.next, second = first, second.next
return

Related

Why does calling a function and writing statements explicitly work differently in Python?

I need an insert to head operation for a linked list that I implemented. However, doing this operation by function call (like insertToHead) and writing the statements explicitly where I need them produces different results. I wonder which property of Python leads to that difference but I couldn't figure it out.
To be more specific, let's say that I have the following class for the linked list:
class Node:
value = None
nextNode = None
def __init__(self, value):
self.value = value
def insertToHead(self, value):
newHead = Node(value)
newHead.nextNode = self
return newHead
For a linked list with a single element (say, 2) I want to insert a node (say, 0) to the head to make linked list 0 -> 2.
I created the linked list the following way
head = Node(2)
Then I tried to insert 0 to head two ways:
Writing the statements explicitly where I need them
newHead = Node(0)
newHead.next = head
head = newHead
Now head is 0, not 0 -> 2.
Calling insertToHead
head = head.insertToHead(0)
head is 0 -> 2 after this statement.
Does anyone know why these two approaches result in differently?
You have a typo. newHead.next should be newHead.nextNode.
A simple implementation of Singly Linked Lists:
class Node:
def __init__(self, value = None, nextNode = None):
self.value = value
self.nextNode = nextNode
class LinkedList:
def __init__(self):
self.head = None # will point to the head of the list
self.tail = None # will point to the tail of the list
self.size = 0 # size of the linked list
def insert_to_head(self, data):
# when push front, the head of the linked list will be Node()
self.head = Node(data, self.head)
if self.tail == None: # if tail is None, means it is a single element
self.tail = self.head
self.size += 1 # increase size by one
def __str__(self):
ret_str = ""
node = self.head
while node != None:
ret_str += str(node.value) + " -> "
node = node.nextNode
return ret_str
myLinkedList = LinkedList()
myLinkedList.insert_to_head(3)
myLinkedList.insert_to_head(2)
print(myLinkedList)

How to generate a linked-list from a standard list in Python

As part of a bigger project, I'm trying to generate a linked-list from a standard list. I've already looked through some topics regarding this problem on SO (e.g. here) but most of codes have much different architecture than mine (linked-list is a class itself). Only the last answer was very similar to my solution.
What I try to accomplish here is to create a generator having, among others, a function creating linked-list from a given input (that's why the structure is rigid here). Also I can't touch ListNode class.
I've tried the following code but it returns only single element linked-list with the last element of the list as a node.
I have a feeling I am close but something is missing. I can create helper functions if that's required but ideally, I would like to avoid it. Has anyone any ideas? Where's the mistake?
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
class Creator:
def populate(self, in_list):
# creating the head node
out_list = ListNode(in_list[0])
curr = out_list
# iterating over input list
for i in in_list[1:]:
curr = curr.next
curr = ListNode(i)
return curr
# Below the manual approach for a list of four elements/nodes
# manual_list = ListNode(1)
# manual_list.next = ListNode(2)
# manual_list.next.next = ListNode(3)
# manual_list.next.next.next = ListNode(4)
inputs = [1,2,3,4]
result = Creator().populate(inputs)
while result:
print(result.val)
result = result.next
Thank you!
You are in the right direction, just take care of the pointer allocation after adding new node, also keep a reference to the first node and return that:
def populate(self, in_list):
# creating the head node
curr = ListNode(in_list[0])
head = curr
# iterating over input list
for i in in_list[1:]:
temp = ListNode(i)
curr.next = temp
curr = temp
return head
Complete code:
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
class Creator:
def populate(self, in_list):
# creating the head node
curr = ListNode(in_list[0])
head = curr
# iterating over input list
for i in in_list[1:]:
temp = ListNode(i)
curr.next = temp
curr = temp
return head
# Below the manual approach for a list of four elements/nodes
# manual_list = ListNode(1)
# manual_list.next = ListNode(2)
# manual_list.next.next = ListNode(3)
# manual_list.next.next.next = ListNode(4)
inputs = [1,2,3,4]
result = Creator().populate(inputs)
while result:
print(result.val)
result = result.next

unable to access next node for Linked List while reversing a Linked List in python

I am a bit new to python and I have seen the correct solutions to the reversing the linkedlist problem but I wanted to know why my solution does not work. In particular, reverse function stays inside the while loop for the code below because of "new_list.head.next=prev" line
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, value):
if self.head is None:
self.head = Node(value)
return
node = self.head
while node.next:
node = node.next
node.next = Node(value)
def __iter__(self):
node = self.head
while node:
yield node.value
node = node.next
def __repr__(self):
return str([v for v in self])
def reverse(linked_list):
new_list = LinkedList()
if linked_list is None:
return new_list
node = linked_list.head
new_list.head = node
while node.next:
prev = node
node = node.next
new_list.head = node
new_list.head.next = prev
return new_list
if __name__ == "__main__":
a = LinkedList()
b = [1,2,3,4,5]
for item in b:
a.append(item)
print a
c = reverse(a)
print c
If you tag your question with Python3 please make sure it runs in python 3.
The reason is because you are mixing up points and creating an infinite loop. Print the value and it may help you find the bug. I am going to use the values to point out the issue.
while node.next:
# First node that comes in value = 1
print(node.value) #
prev = node # prev = 1
node = node.next # node = 2
new_list.head = node # You are setting the head = 2 (i.e. head = node.next)
new_list.head.next = prev # You are setting next of head = 1 (i.e. head.next = node.next.next)
# however this also set node.next.next = 1
# So going into the next loop: node.value = 2 and node.next.value = 1
Because of this pointer confusion you are forever looping between your first and second node.
This is how your reverse can look:
def reverse(linked_list):
new_list = LinkedList()
if linked_list is None:
return new_list
node = linked_list.head
new_list.head = Node(node.value)
while node.next:
node = node.next
prev_head = new_list.head
new_list.head = Node(node.value)
new_list.head.next = prev_head
return new_list
With it I got desired output of print c: [5, 4, 3, 2, 1]
General advise: create new Node instead of assignment to node in initial list.
It's a little easier to reason about this (at least to me) if you think about two references:
• One to the remaining part of the original list you haven't seen
• One to the head of the new list
At each iteration move the remaining up and set the old remaining to the head of the new list. Order is important here — as you've seen it's easy to accidentally change next on two different variables that are pointing the same node if you're not careful:
def reverse(linked_list):
new_list = LinkedList()
if linked_list is None:
return new_list
remaining = linked_list.head
while remaining:
prev_head = new_list.head # the old head becomes the first link
new_list.head = remaining # new head becomese the first remaining
remaining = remaining.next # move remaing one up the chain
new_list.head.next = prev_head # point the new head to the previous
return new_list

How to delete a given node from a linked list using Python

I am trying to learn linked list in Using python,
Could someone please guide me how to delete a particular give node from a linked list?
#!/usr/bin/python
class Node(object):
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
def print_list(node):
while node:
print node,
node = node.next
print
def delete_node(node, node_to_remove):
if first_node == None:
return
pass
# way of creating linked list
def create_linked_list1(n):
linked_list = Node(1)
head = linked_list
for i in range(1, n):
head.next = Node(i)
head = head.next
return linked_list
node1 = create_linked_list1(10)
print_list(node1)
The obvious solution is this:
def delete_by_index(node, index):
for _ in range(index):
prev_node, node = node, node.next
prev_node.next = node.next
However, this won't be able to delete the first node. In order to do that, you need to make it return the new list head, which will normally be the old list head, but will instead be the old second node in the case where you deleted the head. So:
def delete_by_index(node, index):
if not index:
return node.next
head = node
for _ in range(index):
prev_node, node = node, node.next
prev_node.next = node.next
return head
It should be obvious how to simplify this, and you should do so.
Another option is to factor out the "searching" and "deleting" parts. Write an nth function (this should be easy), then you can do this:
def delete_by_index(node, index):
if not index:
return node.next
prev_node = nth(node, index-1)
prev_node.next = prev_node.next.next
return node
If you know about recursive functions, you might also want to figure out how to write either delete_by_index or nth recursively (it's one of the easiest recursive functions to write).
You may also want to trap the error caused by deleting, say, the 15th node of a 10-node list and make it something nicer. Figure out what error you would get in that case (or, if you can't figure it out, just run it and see), then try/except that, and raise an IndexError instead.
While you're at it, you may want to add a delete_by_data(node, data) function and maybe a delete_by_identity(node, child_node) for further practice.
Assume the following singly linked list with a pointer, head, to the first node
head ⇢ n0 → n1 → … → n i - 1 → n i → n i + 1 → … → n N-1 → None
def delete(i):
if i == 0: # there is no prev node, increment head
head = head.next
else:
prev = get_node(i-1) # find prev node, node[i-1]
prev.next = prev.next.next # remove node i
Because this is a singly linked list get_node(i-1) will have to start at head and increment i-1 times to find the node.
NOTE: If this was a doubly linked list, given node[i] you can find node[i-1] using node[i].prev.
v-> w-> x->y> z and if we want to delete x so that new Linked List is v -> w-> y-> z and we have access to only x
position of the next node to x i.e. position of the Node Y
next_node = x.next
swapping the Y to X and then deleting Y `x.data = next_node.data
x.next = next_data.next
Deletion of a node using python in single linked list.
def delete(self,data):
if self.head.data==data:
temp=self.head.next
del self.head
self.head=temp
else:
p=self.head
while p.next.data!=data:
p=p.next
temp=p.next.next
del p.next
p.next=temp
Delete by value:
def delete(head, val):
if head is None:
return None
prev = head
temp = head.next
while temp is not None:
if temp.val == val:
prev.next = temp.next
return val
else:
prev = temp
temp = temp.next
return None

How to find middle element of linked list in one pass in python?

I am trying to solve a linked list problem, to find the middle element in a single pass using python. Could someone please review my code and suggest the best manner to do this?
class Node(object):
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
def print_nodes(node):
while node:
print node
node = node.next
def find_middle(node):
while node:
current = node
node = node.next
second_pointer = node.next
next_pointer = second_pointer.next
if next_pointer is None:
return "Middle node is %s" % str(current)
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
print find_middle(node1)
I merged all the methods for you creating, finding and printing.
class Node(object):
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
def create_linked_list(n):
"""Creating linked list for the given
size"""
linked_list = Node(1)
head = linked_list
for i in range(2, n):
head.next = Node(i)
head = head.next
return linked_list
def print_linked_list(node):
"""To print the linked list in forward"""
while node:
print '[',node,']','[ref] ->',
node = node.next
print '-> None'
def find_middle1(node):
tick = False
half = node
while node:
node = node.next
if tick:
half = half.next
tick = not tick
return "Middle node is %s" % str(half)
def find_middle2(node):
list = []
while node:
list.append(node)
node = node.next
return "Middle node is %s" % str(list[len(list)/2])
node = create_linked_list(10)
print_linked_list(node)
print find_middle1(node)
print find_middle2(node)
Output:
[ 1 ] [ref] -> [ 2 ] [ref] -> [ 3 ] [ref] -> [ 4 ] [ref] -> [ 5 ] [ref] -> [ 6 ] [ref] -> [ 7 ] [ref] -> [ 8 ] [ref] -> [ 9 ] [ref] -> -> None
Middle node is 5
Middle node is 5
Here's on way, it's one pass, though probably not as efficient as you'd like:
def find_middle(node):
list = []
while node:
list.append(node)
node = node.next
return list[len(list)/2]
does that work?
You could keep two pointers, one that moves half as fast as the other.
def find_middle(node):
tick = False
half = node
while node:
node = node.next
if (tick):
half = half.next
tick = not tick
return "Middle node is %s" % str(half)
pseudo code for finding middle element of linked list : -
fast = head
slow = head
while(fast!=null) {
if(fast.next!=null) {
fast = fast.next.next
slow = slow.next
}
else {
break
}
}
// middle element
return slow
All of the above answers are right but for me, this worked best:
def middleNode(self, head: ListNode) -> ListNode:
list=[]
while head:
list.append(head)
head=head.next
return list[floor(len(list)/2)]
Here, using floor helped me otherwise my code gave me errors.
OK, this is NOT a good idea. But it DOES satisfy the constraint of traversing only once. Instead of traversing once (and a secondary half traversal), it (ab)uses the stack to emulate the half traversal (backwards instead of forwards). It's not a good idea, because Python doesn't have an infinitely growable stack (I wish Python would take a cue from the Smalltalk guys on this one), so you really can only handle lists in the size of hundreds, definitely not thousands (this is Python3, btw).
First I modified your script to build bigger lists with the change of a value:
last = root = Node(1)
for i in range(2, 312):
node = Node(i)
last.next = node
last = node
Since we're using the stack and recursion, we need a way to return abruptly out of a deep call stack. So we create an Exception subclass, which is really more of a "notification" than an "exception".
class FoundMiddleNode(Exception):
def __init__(self, node):
super().__init__()
self.node = node
Now for the recursive function:
def probeForMiddle(node, length):
if node.next is None: #recursion stopper
return length
#call recursively
lengthToEnd = probeForMiddle(node.next, length + 1)
#is my distance from start half of what is being returned recursively as the full length?
if (lengthToEnd // 2) - length == 0:
raise FoundMiddleNode(node) #throw an exception to abort the rest of the stack walk
return lengthToEnd
And to use it we do:
try:
probeForMiddle(root, 0)
except FoundMiddleNode as e:
print(e.node)
Not pretty. Not a good idea in anything approximating production code. But a decent example of (ab)using recursion and exceptions to fill the requirement of only traversing once.
The best way to find the middle node is to have two pointers:
P1 = root
P2 = root
While not p2.next == Null:
P1 =p1.next
P2 =P2.next.next
//Linked list
ll = {'A': ["data", "B"],
'B': ["data", "C"],
'C': ["data", "D"],
'D': ["data", "E"],
'E': ["data", None]}
def find_next_node(node="A"):
return ll[node][1] if ll[node][1] else None
def find_mid_node(head="A"):
slow = head
fast = head
while(fast!=None):
for i in range(2):
if find_next_node(fast):
fast = find_next_node(node=fast)
else:
return slow
for j in range(1):
slow = find_next_node(node=slow)
print (find_mid_node())
You can write a smaller code for finding the middle node. Showing the snippet below:
def find_middle(node):
half = node
while node and node.next is not None:
node = node.next.next
half = half.next
return half
Few important points:
Logic will remain the same of keeping two pointers, one fast and other slow.
Write a Linked list class to create a linked list with the help of loop rather than explicitly setting next pointers.
This is very similar to what James and Jordan have posted already, it's just little simpler in terms of what it does and I've added explanation as comments to what's actually doing
class Node:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
# loop through the items and check for next items using two pointers (fast and slow)
# set the speed for fast twice higher than the slow pointer so when when fast reaches
# the end the slow would be in the middle
def find_middle(head ):
fast = slow = head
#slow = head
while fast.next != None and fast.next.next != None:
fast = fast.next.next
slow = slow.next
# slow is now at the middle :)
print (slow.data )
#setup data
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
find_middle(node1)
I might be little late but this works best for me. Writing complete code for creating, finding the midpoint & printing the linked list.
class Node:
'''
Class to create Node and next part of the linked list
'''
def __init__(self,data):
self.data = data
self.next = None
def createLL(arr):
'''
linked list creation
'''
head = Node(arr[0])
tail = head
for data in arr[1:]:
tail.next = Node(data)
tail = tail.next
return head
def midPointOfLL(head):
'''
Here, i am using two pointers slow and fast, So idea is fast will be 2 times faster than slow pointer
and when fast reaches the end of the linked list slow pointer will be exactly in the middle.
'''
slow = head
fast = head
if head is not None:
while (fast.next is not None) and (fast.next.next is not None):
slow = slow.next
fast = fast.next.next
return slow
def printLL(head):
curr = head
while curr :
print(curr.data,end = "-->")
curr = curr.next
print('None')
arr = list(map(int,input().split()))
head = createLL(arr)
midPoint = midPointOfLL(head)
print(midPoint.data)
printLL(head)
list=['ok','go','no','poi','duo','ok','go','nah']
b=0
b=int(len(list)/2) #print the middle element change .5 values
print(list[b])
if((len(list)%2)==0): #if list is of even number print both middle values
print(list[b+1])
when i searched this question i was looking for something like this so i can get both middle values when entered even num of elements
there must be a better way to do it i just start coding from like 3,4 day

Categories