Linked List and array - python

I know StackOverflow isn't writing the question and getting the answer site but here is my problem from leetcode.
l1 = input()
l2 = input()
def f(x): #Gives reversed of linkedlist ex. [2, 4, 3] return 342
a, u = 0, 0
for ele in x:
if ele.isnumeric():
a += int(ele)*(10**u)
u += 1
return a
l = list(int(i) for i in str(f(l1) + f(l2)))
print(list(reversed(l)))
This question is leet code problem so here I have solved the problem but this is something different they do not want spaces between the number after comma.
Input: [2,4,3]
[5,6,4]
My output:
[7, 0, 8]
Expected output: [7,0,8]
However, I also tried
k = str(f(l1) + f(l2))
print("[" + ",".join(str(k)[::-1]) + "]")

You aren't supposed to use input() and print() on leetcode
When you start a problem they give you a function you have to fill and return the result.
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
#put your code here
return the_result
This problem is supposed to use a linked list with nodes defined as
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
this is what should be the input of the addTwoNumbers() method you are supposed to code.
But somehow by using input() you are bypassing this and grabbing the raw list.
Also, prints(stdout) are not what is being evaluated by the leetcode system, they look for the output of addTwoNumbers() which in this case is blank.

Here is the complete solution;
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def __init__(self):
self.head = None
def rev(self, ls):
res = []
self.head = ls
while self.head:
res.append(str(self.head.val))
self.head = self.head.next
return list(reversed(res))
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
res1 = int(''.join(self.rev(l1)))
res2 = int(''.join(self.rev(l2)))
res3 = str(res1 + res2)
resls = list(reversed([i for i in res3]))
self.head = ListNode(resls[0], None)
finalres = self.head
for i in range(1, len(resls)):
lsn = ListNode(resls[i], None)
finalres.next = lsn
finalres = finalres.next
return self.head
**Explanation**:
I will asume that you know the basics of linked lists i.e, what are they (in case you have confusion please comment).
So in the Solution class, i simply defined a self.head attribute inside its __init__ method which i am going to use to keep track of elements in a linked list. It is initially set to None as right there we don't have any data there.
Then i defined a rev method to reverse the given linked list.
Inside the rev, i created an empty list res to store the data from the linked lists provided.
Rev also takes a linked list as an argument as i will take the data from it and append it to the res list
So i put self.head equal to that linked list ls provided when we call the method.
Then i simply ran a while loop until self.head is defined (i.e, until it is not None which means there is still data).
After every iteration, i kept changing self.head to self.head.next to move forward in the linked list and grab the data from every node of that linked list and append that to res list.
At the end i simply returned the reversed res.
Then i defined another method, addTwoNumbers which takes two linked lists and returns there sum as per the requirement.
First of all i need those two linked lists to be in integer form and reversed ( as per condition). So i used the rev method to reverse them, join method (inbuilt method in python to join a list of strings) to convert the list to string and then int method to convert the string to int.
I did the same with both of the linked lists and stored them in res1 and res2 respectively.
Then i took their sum (res3) and converted it to string as we cannot iterate over an integer .
Then i converted the res3 to a reversed list .
Now the last step, return the whole thing as a listnode.
So i simply created an instance of ListNode;
self.head = ListNode(resls[0], None)
This will create an instance of ListNode with data as first element of resls and next as none.
Then i stored it inside another variable to refrence to the same instance and don't change it.
Then ran a far loop on the remaining elements and kept adding data and next.
Hope you understood. Thanks.

That is just the default representation of a list, it has a space after each comma
x = [1, 2, 3]
print(x) # [1, 2, 3] type is list
print(str(x).replace(" ", "")) # [1,2,3] type is str

Related

Appending a doubly circular linked list to the end of another doubly circular list (Python)

So I have an assignment that ask me to append a doubly circular linked list to the end of another doubly circular list. For example, I have two doubly circular linked lists which are [0,1,2,3] and [10,11,12,13]. The output should be [0,1,2,3,10,11,12,13], and we also have to make it reversed which is [13,12,11,10,3,2,1,0]
My assignment provides two py files. The first one is called "linked_list.py". It's for creating a doubly circular linked list. I cannot modify this file.
class Node:
def __init__(self, x):
self.data = x
self.next = None
self.pre = None
class DoubleLinkedList:
def __init__(self):
self.head = None
def insertHead(self, x):
self.head = Node(x)
self.head.next = self.head
self.head.pre = self.head
def insert(self, y, x):
tmp = self.head
nodex = Node(x)
while True:
if tmp.data == y:
break
tmp = tmp.next
nodex.next = tmp.next
nodex.pre = tmp
tmp.next.pre = nodex
tmp.next = nodex
def printForward(self):
print("Forward :",end=" ")
tmp = self.head
print(tmp.data,end=" ")
tmp = tmp.next
while tmp!=self.head:
print(tmp.data,end=" ")
tmp=tmp.next
print()
def printBackward(self):
print("Backward :",end=" ")
tmp = self.head.pre
print(tmp.data,end=" ")
tmp = tmp.pre
while tmp!=self.head.pre:
print(tmp.data,end=" ")
tmp=tmp.pre
print()
The second code is "combine.py"
from linked_list import Node, DoubleLinkedList
def combine(l1, l2):
#This is the main part of this assignment, write a function that can combine two doubly circular linked lists.
#There's no need to return value since we directly modify LL1 as our final result
if __name__=="__main__":
LL1 = DoubleLinkedList()
LL1.insertHead(0)
LL1.insert(0, 1)
LL1.insert(1, 2)
LL1.insert(2, 3) #LL1 = [0,1,2,3]
print(LL1)
LL2 = DoubleLinkedList()
LL2.insertHead(10)
LL2.insert(10, 11)
LL2.insert(11, 12)
LL2.insert(12, 13) #LL2 = [10,11,12,13]
print(LL2)
combine(LL1, LL2)
LL1.printForward() # This function can print the combined linked list
LL1.printBackward() # This function can reverse the
# Forward output : 0 1 2 3 10 11 12 13
# Backward output : 13 12 11 10 3 2 1 0
At first I was thinking about using the same method as appending normal linked list but I realized that the last node of circular linked list will point at the first node. Then I got confused by the whole assignment. How can I make one doubly circular linked list get appended to the end of another doubly circular linked list? Some detailed explanations are appreciated. Thanks in advance.
Basically, you will need to append the complete l2 chain between head and head.pre of l1. In order to do so, I see two different methods:
The naive one (complexity: O(n))
Simply reuse the methods that were nicely provided to you. In the end, you are just asked to add multiple values at the end of l1:
def combine(l1, l2):
l1_tail_val = l1.head.pre.data
l2_head = l2.head
l1.insert(l1_tail_val, l2_head.data)
l2_head = l2_head.next
l1_tail_val = l2_head.data
while l2_head != l2.head:
l1.insert(l1_tail_val, l2_head.data)
l1_tail_val = l2_head.data
l2_head = l2_head.next
This method will need to iterate over l2 entirely, so if the list is big, it can take some time.
Edit: This is even worse than that, since in order to find the insert place, the insert method will iterate over l1, always to find that the wanted insert location is at the end. So this is closer to O(n^2) than O(n)
The efficient one (complexity: O(1))
With this one, you don't have to iterate over anything, you just need to connect the nodes so that it forms a single circular list:
def combine(l1, l2):
l1_tail = l1.head.pre
l1_head = l1.head
l2_tail = l2.head.pre
l2_head = l2.head
# Now just update the references
# Then end of l2 should be connected to the head of l1 (same for the reverse relation)
l1_head.pre = l2_tail
l2_tail.next = l1_head
# The start of l2 should be connected to the end of l1 (same for the reverse relation)
l1_tail.next = l2_head
l2_head.pre = l1_tail
This does not rely on any loop or recursion, thus giving you a constant complexity, no matter the lists lengths

Why am I getting a NoneType error after reversing a linked list and processing the head of the new linked list?

I am writing code to answer the following question: "for two linked lists l1 and l2 that contain positive integers (and have at least one node), return their sum as a linked list. "
For example:
Input: l1 = [7,2,4,3], l2 = [5,6,4]
Output: [7,8,0,7]
The way I am coding this is to reverse both linked lists, then add them (add this is how you would add two numbers)
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
if l1==[0]:
return l2
if l2==[0]:
return l1
#Reversing both linked lists l1 & l2
prev = None
pointer = l1
while pointer:
curr = pointer.next
pointer.next = prev
prev = pointer
pointer = curr
prev2 = None
pointer2 = l2
while pointer2:
curr2 = pointer2.next
pointer2.next = prev2
prev2 = pointer2
pointer2 = curr2
#prev and prev2 are the heads of the reversed linked list(I've tested this)
#Creating a new linked list that is the addition of the two reversed linked list
l3=ListNode(0)
start_l3 = l3
carry = 0
while prev or prev2:
if prev.val + prev2.val >9:
carry =1
else:
carry = 0
s = prev.val + prev2.val + carry
l3.next = ListNode(s)
l3=l3.next
prev=prev.next
prev2=prev2.next
if carry ==1:
l3.next = ListNode(1)
return start_l3.next
When I run this for the input given above, I get a "NoneType object has no attribute val for the line if prev.val + prev2.val >9:
Any ideas why this is? Because when I test prev and prev2; it does seem to return the reversed linked list.
The reason for the error is that you cannot assume that both prev and prev2 are not None. Your while condition only guarantees that at least one of them is not None, but not both. So that means you still need to have a None check inside the body of the loop.
There are also some other issues:
l1==[0]: is not correct. The left side of this comparison is a linked list instance, while the right side is a standard list. These comparisons will always be False, and so you can just omit them
You are adding the carry to the wrong sum. You should add the carry from the previous iteration to the current sum, so things are currently happing in the wrong order.
The resulting list should be reversed. You can do this on the fly by prefixing each node to l3, instead of appending it. This will also make it unnecessary to create a dummy ListNode(0) before the final loop. You can just start with None.
Your code mutates the original input lists. This will be acceptable on code challenge sites, and be efficient, but it is bad practice. The caller should not be unpleasantly surprised that the lists they provide as input have been reversed by a call to this addTwoNumbers function. You can solve this in several ways, but it is probably easiest to reverse them a second time to undo that operation.
To avoid repetition of code, you should create a reverse function
I'll assume that the ListNode constructor can take a second argument for initialising its next reference:
class ListNode:
def __init__(self, val, nxt=None):
self.val = val
self.next = nxt
Then the corrected code could be:
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
def reverse(lst: ListNode):
prev = None
node = lst
while node:
curr = node.next
node.next = prev
prev = node
node = curr
return prev
#Reversing both linked lists l1 & l2
l1 = reverse(l1)
l2 = reverse(l2)
#Creating a new linked list that is the addition of the two reversed linked list
node1 = l1
node2 = l2
l3 = None
carry = 0
while node1 or node2:
added = carry # The carry from the previous iteration should be used
if node1: # You must have this check
added += node1.val
node1 = node1.next
if node2:
added += node2.val
node2 = node2.next
carry = added // 10 # Simpler way to get the carry
l3 = ListNode(added % 10, l3) # Prefix(!) the new node
if carry == 1:
l3 = ListNode(1, l3)
# Restore the input lists:
reverse(l1)
reverse(l2)
return l3
Further remarks
Concerning the prefixing of nodes into the final list l3:
This is the main statement for doing that:
l3 = ListNode(added % 10, l3)
Let's break this down:
The constructor is called with two arguments:
val = added % 10: this is one digit, so in case added is 14, this expression will evaluate to just 4 (the 1 will go to the carry).
nxt = l3: this is the current (incomplete) list. The first time it is None.
The constructor then assigns these values as attributes of the new node that is being initialised:
self.val = val
self.next = nxt
So here we see that the value of nxt, is assigned to the new node's next attribute. As we passed l3 as argument, we are actually doing:
self.next = l3
By that statement we effectively prefix the new node to the list: the new node becomes the first node of the list. Moreover, self acts as the head of that list, which is now one node longer. We want to keep track of this new head, and so we assign the new node back to l3:
l3 = ListNode(added % 10, l3)
As the first time l3 was None, this will just create a one-node list, whose next attribute is that None. But the second time this is executed, we get a new node whose next refers to the "existing" node, so now we have a list of two... etc.
Sometimes it can come in handy to start a linked list with a dummy node like ListNode(0), which then later can be removed. However, in this revised algorithm that would not help, and so we start with None, which after the first iteration of the loop will serve as second argument to the ListNode constructor, which in turn will use it to initialise the next attribute of the new node. This new node will remain the tail of the list as other nodes are prefixed to it.

how do we organise a linked-list recurrence relation to merge two sorted linked list?

I have edited the code to incorporate the notes from below (from Trincot), the only thing I am still not clear about is the "l1.next= MergeTwoLists(l1.next,l2)" ; I still don't think this is right- any ideas how to amend this?
Also, do I need a while statement, since the recursive call seems to loop in some sense already.
Input: l1 = [1,2,4], l2 = [1,3,4]
Output: [1,1,2,3,4,4]
def MergeTwoLists(l1,l2):
prehead = ListNode(-1)
pointer_run = prehead
#Base Case
if not l1:
return l2
if not l2:
return l1
#Recurrence Relation
while l1 or l2:
if l1.val < l2.val:
pointer_run.next = l1
l1_temp = l1.val
l1.next= MergeTwoLists(l1.next,l2)
else:
pointer_run.next = l2
l2.next = MergeTwoLists(l1,l2.next)
return prehead.next
I am getting None as the output.
This happens when l2.val == l1.val. This is a case that is not captured by any if in your code, and so prehead.next is executed. But that next attribute never received a value other than the initial value, which I suppose is set to None by the ListNode constructor.
There are the following issues:
The last if should really be an else, as you want to capture the above described case in one of those two blocks. As both these blocks (the if block and now else block) end with a return, there should be no possibility to ever get to return prehead.next: that statement can be removed. That also means that prehead is never read after its next attribute is assigned a value, and therefore serves no purpose.
return MergeTwoLists(l1.next,l2) is not correct. You need to assign the returned value to l1.next. And to avoid that you mutate the input lists, you should first make a new node with the value at l1 and assign to that new node's next attribute. The same is true for the mirrored situation.
The first base case is not necessary, as it is covered by the next.
As ListNode was not given, I add the definition that I will use in the corrected code:
class ListNode:
# Constructor allows caller to optionally provide a next node
def __init__(self, val, nxt=None):
self.val = val
self.next = nxt
# A method to ease the iteration of all list values
def values(self):
yield self.val
if self.next:
yield from self.next.values()
# Define the representation of a list (e.g. for printing)
def __repr__(self):
return " → ".join(map(repr, self.values()))
# A class method to ease the creation of a list
#classmethod
def fromvalues(cls, *values):
head = None
for val in reversed(values):
head = cls(val, head)
return head
Here is the corrected function:
def MergeTwoLists(l1, l2):
if not l1:
return l2
if not l2:
return l1
if l1.val < l2.val:
return ListNode(l1.val, MergeTwoLists(l1.next, l2))
else:
return ListNode(l2.val, MergeTwoLists(l1, l2.next))
Here is how you can run it:
l1 = ListNode.fromvalues(1, 2, 4)
l2 = ListNode.fromvalues(1, 3, 4)
result = MergeTwoLists(l1, l2)
print(result) # 1 → 1 → 2 → 3 → 4 → 4

Sort a linked list, handling pairs as a single item

I am working on this challenge:
Sort a Linked list in increasing order by considering two nodes as a two digit number. (in place sorting)
4 ≤ n ≤ 1000
The length of the linked list is always even.
Example 1:
Input
1→3→4→2→1→2
Output
1→2→1→3→4→2
Explanation:
12 > 13 > 42
Example 2:
Input
1→3→0→3
Output
0→3→1→3
Here is my linked list template implementation; which anyone can start coding:
class Node():
def __init__(self,val):
self.data = val
self.next = None
class Linkedlist():
def __init__(self):
self.head = None
def add(self,x):
t = Node(x)
t.next = self.head
self.head = t
def display(self):
p = self.head
while p != None:
print(p.data)
p=p.next
def sort(self):
curr = self.head
# your logic here
m = Linkedlist()
m.add(1)
m.add(3)
m.add(4)
m.add(2)
m.add(1)
m.add(2)
m.display()
Which is the algorithm to sort the pairs in a linked list (in place), and how can I code it?
First write a function that accepts a linked list of single digit nodes and merges each pair of adjacent single digit nodes into a linked list of half as many nodes, where each node contains a double digit number.
Then sort the resulting linked list using bubble sort, which is O(n^2), or mergesort, which is O(nlogn).
Then, if need be, write a third function that takes apart the double digit nodes and creates a new list of twice as many single digit nodes.
Doing it with two or three functions like this will really simplify the sort.
First of all, your current code will not generate list 1→3→4→2→1→2, but its inverse. This is because your definition of the add method will prepend the given value to the list.
To make add work correctly, it should first find the last node in the list, and append the new node after it. As this is not a very efficient method to add many values to a list, I would suggest to also define add as a Node method, and to allow chaining add calls. That way you can add many values in one chained expression without being inefficient.
Also, as you will need to compare values of pairs, it makes sense to make a method on Node that will return the value of the pair formed by that node and the next in the list.
Finally, for the sort algorithm itself, you could reduce the list to its first pair only (which is then obviously sorted), and treat the rest as a separate list of unsorted nodes. Then extract a pair at a time from the unsorted list, and find the right place to inject it in the main list, so that it remains sorted.
This process represents O(n²) time complexity on average and in the worst case. The best case is O(n), which occurs when the list is originally sorted in reverse order.
Here is how that could look:
class Node():
def __init__(self, val):
self.data = val
self.next = None
# Easy chaining: defining this method on a Node as well
def add(self, val):
node = Node(val)
node.next = self.next
self.next = node
return node
# Define how the value of a pair is calculated
def pairvalue(self):
return self.data * 10 + self.next.data
class Linkedlist():
def __init__(self):
self.head = None
def add(self, val):
# Corrected method: addition should be at the end of the list
node = Node(val)
if not self.head:
self.head = node
else: # Look for the last node in the list
curr = self.head
while curr.next:
curr = curr.next
# ...and append the new node after it
curr.next = node
return node # Allow for chaining
def display(self):
p = self.head
while p:
print(p.data, end= "→")
p = p.next
print("NIL")
def sort(self):
if not self.head:
return
# Reduce list to just its first pair
# The remainder is a temporary "todo" list
todo = self.head.next.next
self.head.next.next = None
while todo:
pair = todo # The pair that will be added to the sorted list
todo = todo.next.next
val = pair.pairvalue()
if val < self.head.pairvalue():
# The pair is a minimum: prepend it
pair.next.next = self.head
self.head = pair
else:
curr = self.head.next # odd index
# Find insertion point in sorted list
while curr.next and curr.next.pairvalue() < val:
curr = curr.next.next
# Perform insertion
pair.next.next = curr.next
curr.next = pair
m = Linkedlist()
m.add(1).add(3).add(4).add(2).add(1).add(2)
m.display() # original list
m.sort()
m.display() # final list
The output:
1→3→4→2→1→2→NIL
1→2→1→3→4→2→NIL

Circular list detection in Python?

Is there a way to detect the first element of a circular list in Python? In Java and C++ you can just establish a pointer to the first element.
Question I came across: Given a circular linked list, implement an algorithm which returns the node at the beginning of the loop.
A circular linked list has no true beginning & end. But from your comment, I think you want to detect when you reach the element you started with while looping through the list.
#The structure of ListNode
class ListNode:
def __init__(self, val):
self.val = val
self.next = None
# Supposes you have a circular linked list and you have a reference to head. You can do as follows to print the whole list.
current = head.next
while current != head: # stop when it comes back to head
print current.val
current = current.next
I think you need a depth first search to answer this in generality, here's the sort of thing:
a = [1,2,3]
b = [4,5,6]
a[1] = b
b[2] = a
def is_list(l):
try:
it = iter(l)
return l
except TypeError:
return None
def dfs(a, colors):
l = is_list(a)
print 'is_list:', l
if l:
if colors.has_key(id(l)):
print 'cycle detected'
return l
colors[id(l)] = ''
for ll in l:
dfs(ll, colors)
colors = {}
dfs(a, colors)

Categories