How do you populate values into a class in python - python

I have a code that works for merging 2 linked lists for leetcode. However, upon testing it, I am facing a bottleneck. How do I populate the ListNode with a list? the following outputs just 1 whatever, not the merged linked list.
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def __str__(self):
return str(self.val)
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
place_holder = ListNode()
tmp = place_holder
while list1 and list2:
if list1.val < list2.val:
tmp.next = list1
list1 = list1.next
else:
tmp.next = list2
list2 = list2.next
tmp = tmp.next
if list1 is None:
tmp.next = list2
if list2 is None:
tmp.next = list1
return place_holder.next
#input the two integer lists
l1 = [1, 2, 4]
l2 = [1, 3, 4]
list1 = ListNode(l1[0])
list2 = ListNode(l2[0])
list_result = Solution().mergeTwoLists(list1, list2)
print(list_result)

Fix your __str__ so it prints the whole linked list:
def __str__(self):
s = f"({str(self.val)})"
if self.next:
s += f" -> {self.next}" # be careful not to build any circular lists...
return s
and now you can see the actual result of your merge function:
(1) -> (1)
which is 100% correct (at least for these inputs) because you merged the lists (1) and (1).
Writing a function that lets you turn a list of multiple numbers into a single linked list will make it easier to test this logic with longer inputs. One option would be to just do this in your ListNode constructor:
from typing import List, Optional, Union
class ListNode:
def __init__(self, val: int = 0, *vals: int) -> None:
self.val = val
self.next = ListNode(*vals) if vals else None
def __str__(self) -> str:
s = f"({str(self.val)})"
if self.next:
s += f" -> {self.next}"
return s
Now you can do:
list1 = ListNode(1, 2, 4)
list2 = ListNode(1, 3, 4)
list_result = Solution().mergeTwoLists(list1, list2)
print(list_result) # (1) -> (1) -> (2) -> (3) -> (4) -> (4)

You need a way to convert a regular Python list to a linked list. Your nodes are initialized with one integer each (never mind that it came from l1 and l2), so they can't grow any next elements by themselves. To fix it, add a static method to ListNode that accepts a list:
class ListNode:
#static
def fromList(lst):
if not lst:
return None
return ListNode(lst[0], next=ListNode.fromList(lst[1:]))
This will recursively convert a Python list into a linked list. Then you can initialize your linked lists like this:
list1 = ListNode.fromList(l1)
list2 = (same)

You need to convert your list value into a List value. (I recommend using separate classes for nodes and the list that consists of those nodes.)
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
def __str__(self):
return str(self.val)
class List:
def __init__(self, values=None):
# Dummy node that is independent of any actual
# data. You can store the length (or really, any
# metadata you like) in the dummy node.
self.head = ListNode(0)
if values is None:
values = []
for x in values:
self.append(x)
def append(self, value):
...
list1 = List(l1)
list2 = List(l2)
You'll need to implement List.append, and possibly some other methods. It's better to do all the pointer wrangling in List itself and to provide methods for mergeTwoLists to construct the resulting List.

Related

Want to create a program to scale a linked list by a certain factor

I want to write a function where you input a linked list and a factor, and the function returns a new linked list scaled by that factor. For example:
scale(linkify([1, 2, 3]), 2)
2 -> 4 -> 6 -> None
First, I made a function that, when you input a list of items, converts into a linked list. This is it here:
def linkify(item: list[int]) -> Optional[Node]:
"""Return a Linked List of Nodes with same values and same order as input list."""
if len(item) == 0:
return None
elif len(item) == 1:
return Node(item[0], None)
else:
return Node(item[0], linkify(item[1:]))
Now, I'm trying to write the function in order to scale that list.
Here is what I have now for the function:
def scale(head: Optional[Node], factor: int) -> Optional[Node]:
"""Returns new linked list of nodes where each value in original list is scaled by scaling factor."""
if head is None:
return None
else:
return Node(head.data * factor, scale(head.next, factor))
However, when I try to test this, I get an error saying exercises.ex11.linked_list.Node object at 0x0000013392C97C10>, and I'm not entirely sure what this means. Can anyone tell me what I'm getting wrong?
Also, I have to create the function recursively, and can't use any other functions outside the ones I've created.
Here is the test case I created as well:
def test_scale_factor() -> None:
linked_list: list[int] = [1, 2, 3]
linked_list_2: list[int] = [2, 4, 6]
assert is_equal(scale(linkify(linked_list), 2), linkify(linked_list_2))
Thanks for your help!
Is this a proper solution for your case?
I always try to avoid using recursions.
Sure you also can add some checks on the function inputs.
class Node:
def __init__(self, data = None):
self.data = data
self.next = None
class Linkedlist:
def __init__(self):
self.head = None
def linkify(self, nodes):
if len(nodes) == 0:
return
self.head = node = Node()
for i in nodes:
node.next = Node(i)
node = node.next
self.head= self.head.next
def is_equal(self, other_llist):
node1 = self.head
node2 = other_llist.head
while node1 and node2:
if node1.data != node2.data:
return False
node1 = node1.next
node2 = node2.next
if node1 or node2:
return False
return True
def scale(self, factor):
node = self.head
while node:
node.data *= factor
node = node.next
llist1 = Linkedlist()
llist1.linkify([1, 2, 3])
llist1.scale(2)
llist2 = Linkedlist()
llist2.linkify([2, 4, 6])
print(llist1.is_equal(llist2))

Driver code for Leet Code problem "Intersection of two linked lists"

I am looking at Leet Code problem 160. Intersection of Two Linked Lists:
Given the heads of two singly linked-lists headA and headB, return the node at which the two lists intersect. If the two linked lists have no intersection at all, return null.
For example, the following two linked lists begin to intersect at node c1:
The test cases are generated such that there are no cycles anywhere in the entire linked structure.
Note that the linked lists must retain their original structure after the function returns.
I am trying to find the driver code for the following solution, but have been unsuccessful. How can I run this code for some example input?
Class Solution:
def getIntersectionNode(self, headA, headB):
Alst = {}
while headA is not None:
Alst[headA] = headA
headA = headA.next
while headB is not None:
if headB in Alst:
return headB
headB = headB.next
return None
On Leet Code the input is parsed and linked lists are created before the solution code is executed.
Here are some functions you could use for problems like these:
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def createLinkedList(values):
head = None
if values:
itertor = iter(values)
node = head = ListNode(next(itertor))
for value in itertor:
node.next = ListNode(value)
node = node.next
return head
def intersectLinkedLists(intersectValue, listA, listB, skipA, skipB):
if intersectValue == 0:
return
for _ in range(skipA-1):
listA = listA.next
for _ in range(skipB):
listB = listB.next
listA.next = listB
if listA.next.val != intersectValue or listB.val != intersectValue:
raise ValueError("Intersection value not found")
return listB
Add to that your solution code:
class Solution(object):
def getIntersectionNode(self, headA, headB):
Alst = {}
while headA is not None:
Alst[headA] = headA
headA = headA.next
while headB is not None:
if headB in Alst:
return headB
headB = headB.next
return None
And finally, define some input. Here is how that would look for the example input that Leet Code loads by default:
# Inputs
intersectionValue = 8
valuesA = [4,1,8,4,5]
valuesB = [5,6,1,8,4,5]
skipA = 2
skipB = 3
# Conversion
listA = createLinkedList(valuesA)
listB = createLinkedList(valuesB)
intersection = intersectLinkedLists(intersectionValue, listA, listB, skipA, skipB)
# Run solution code
s = Solution()
answer = s.getIntersectionNode(listA, listB)
# Verify
print("Correct" if answer == intersection else "Wrong")
pretty intuitive solution:
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
cur_A,cur_B =headA,headB
len_A =0
while cur_A:
cur_A =cur_A.next
len_A+=1
len_B =0
while cur_B:
cur_B =cur_B.next
len_B+=1
# So far found the length of both linked lists
# Now decide which one is short_list or long_list
if len_A >len_B:
long_list =headA
short_list =headB
diff =len_A -len_B
else:
long_list =headB
short_list =headA
diff =len_B -len_A
i=0
while i<diff:
long_list=long_list.next
i+=1
# at this point we are at the same level of both l inked lists
while long_list!=short_list:
long_list=long_list.next
short_list=short_list.next
return long_list

How to test programs related to linked lists in Python

For example, merge 2 sorted linked lists.
I understand the code for solving the problem. However, how to create two linked lists and see the output? I have the same problem with trees. If I know how to test the input, it will be very helpful.
Input: l1 = [1,2,4], l2 = [1,3,4]
Output: [1,1,2,3,4,4]
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
For testing solutions with linked lists it helps to have functions (or methods) which translate linked lists to lists and vice versa. So define these:
def to_linked_list(iterable):
head = None
for val in reversed(iterable):
head = ListNode(val, head)
return head
def to_native_list(head):
lst = []
while head:
lst.append(head.val)
head = head.next
return lst
Now you can more easily test your solution:
l1 = to_linked_list([1,2,4])
l2 = to_linked_list([1,3,4])
result = Solution().mergeTwoLists(l1, l2)
print(to_native_list(result))
If you're looking for a test case: try something like this
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
l1 = ListNode(1)
l1.next = ListNode(2)
curr = l1.next
curr.next = ListNode(4)
l2 = ListNode(1)
l2.next = ListNode(3)
l2.next.next = ListNode(4)
I'll leave creating the solution list up to you.

Python Linked List Merge Sort not working

I have this assignment for uni that I have been working on for some time now, but I can't seem to figure out what's wrong. The goal is to merge two already-sorted linked lists into one sorted linked list.
The only function that I am allowed to change is the merge(a,b) function. I triple-checked, but I keep getting the following error:
in __repr__
out += str(node.weight)
AttributeError: 'ItemList' object has no attribute 'weight'
Is there anyone that can figure out what I should change? I'm very lost.
My code:
from __future__ import annotations
from typing import Optional
from dataclasses import dataclass
#dataclass
class Node:
weight: float
link: Optional[Node] = None
def merge(a: ItemList, b: ItemList) -> c:
"""
This function takes two linked lists, assumed sorted, and merges them
in-place, without creating new Nodes, just by changing the links.
"""
# create a new ItemList and dummynode as head:
c = ItemList()
c.head = Node(0)
# List1 is empty then return b
if a.head is None:
c._length += len(b)
b._length -= len(b)
return b
# if List2 is empty then return a
if b.head is None:
c._length += len(a)
a._length -= len(a)
return a
# If the weight of the element of a is smaller or equal to b's weight
if a.head.weight <= b.head.weight:
# We assign the weight of a's head to the head of c
c.head.weight = a.head.weight
#Give list a a new head (depletion) and subtract one from the length of a
a.head = a.head.link
a._length -= 1
# We will go through the algorithm again (recursively) to check for the element next-in-line.
c.head.link = merge(a, b)
# If the weight of the element of a is smaller or equal to b's weight
else:
# We assign the weight of a's head to the head of c
c.head.weight = b.head.weight
#Give list b a new head (depletion) and subtract one from the length of b
b.head = b.head.link
b._length -= 1
# We will go through the algorithm again (recursively) to check for the element next-in-line.
c.head.link = merge(a, b)
# return the merged list
return c
class ItemList:
head: Optional[Node]
def __init__(self):
"""Initialize an empty linked list for warehouse items."""
self.head = None
self._length = 0
def __len__(self) -> int:
return self._length
def insert(self, val: int) -> ItemList:
"""Insert a new item with given weight, at the beginning of the list"""
new_node = Node(weight=val, link=self.head)
self.head = new_node
self._length += 1
return self
def __repr__(self):
"""This function prints the list in a nice way."""
node = self.head
out = "["
while node is not None:
out += str(node.weight)
if node.link is not None:
out += ", "
node = node.link
out += "]"
return out
warehouse = (
ItemList()
.insert(8)
.insert(6)
.insert(4)
.insert(2)
.insert(0)
)
warehouse2 = (
ItemList()
.insert(9)
.insert(7)
.insert(5)
.insert(3)
.insert(1)
)
print(merge(warehouse,warehouse2))
You could write a recursive mergeNodes function:
def mergeNodes(a: Node, b: Node):
"""
This function takes two linked lists of Nodes, assumed sorted, and
merges them into a single linked list of Nodes, in-place, without
creating new Nodes, just by changing the links.
"""
if a is None:
return b
if b is None:
return a
if a.head.weight <= b.head.weight:
a.link = mergeNodes(a.link, b)
return a
else
b.link = mergeNodes(a, b.link)
return b
Merging the lists becomes very simple:
def merge(a: ItemList, b: ItemList) -> ItemList:
"""
This function takes two ItemList objects, assumed sorted, and merges them
into a new ItemList, without creating new Nodes, just by changing the links.
the original objects are destroyed
"""
# create a new ItemList:
c = ItemList()
c._length = a._length + b._length;
c.head = mergeNodes(a.head, b.head)
# clear the original lists because the links are no longer consistent
a._length = 0
a.head = None
b._length = 0
b.head = None
return c
Note that merge should be a method of class ItemList and merge a list passed as an argument into self.

Changing characters and reversing chained lists. (python)

Well, I was supposed to do the following:
Using the class Node (classic construction)...
class No:
def __init__(self, valor, prox):
self.valor = valor
self.prox = prox
to make a function that when called will swap the 2nd and 3rd characters of a chained list and add a backward chained list to the end of the original one. So if we do function(list), being lista = No(1, No(4, No(2, None))) (1>4>2) it will return (1>2>4>4>2>1).
The problem with that is that I solved the problem by adding the terms to regular lists and messing with them there. However, then I found out I was supposed to only use chained lists (that node class I put above) and now I'm a bit clueless...
Code for the wrong solution:
class No:
def __init__(self, valor, prox):
self.valor = valor
self.prox = prox
def printLista(lista):
global lista1
lista1 = []
while lista:
lista1.append(lista.valor)
lista = lista.prox
return lista1
def printbackwards(lista):
global lista2
if lista == None: return
printbackwards(lista.prox)
lista2.append(lista.valor)
def swapprint(lista):
global lista1, lista2
i = 0
lista2 = []
printlist(lista)
printbackwards(lista)
for i in range(len(lista1)):
print lista1[i], lista2[i],
lista = No(3, No(1, No(4, No(2, None))))
swapprint(lista)
class No:
def __init__(self,a,b):
self.val = a
self.next = b
def __str__(self):
return "%s->%s"%(self.val,self.next)
def swapandReverse(lista):
n2 = lista.next #2nd element
n2.val,n2.next.val = n2.next.val,n2.val #swap 2,3
n = lista #root node
v = [] #hold our values
while n.next:
v.append(n.val) #add our value to list
n = n.next #move to next node
v.append(n.val) #append value of last node in the list
while len(v): #as long as we have values left in list
n.next = No(v.pop(-1),None) #set next to new node with our val
n = n.next
lista = No(3,No(1,No(4,No(2,None))))
print lista
swapandReverse(lista)
print lista
at least something like that
It shouldn't be necessary to use global variables for your linked-list operations. Instead, you just need to recurse in the right way, and return any values up the call-stack. I'm not sure if I've understood what you're supposed to do, since your print functions don't actually print anything, but here's what you can do if you are supposed to create a new list from an old one:
class Node(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
def __str__(self): # borrowed from Joran Beasley's answer
return "%s->%s" % (self.value, self.next)
def reverse_linked_list(lst, tail=None):
if lst is None:
return tail
else:
return reverse_linked_list(lst.next, Node(lst.value, tail))
def swap_23_linked_list(lst):
try:
second = lst.next
third = second.next
except AttributeError: # probably lst or lst.next is None!
raise ValueError("list is too sort to swap second and third values")
new_third = Node(second.value, third.next) # reuse all the nodes past third!
new_second = Node(third.value, new_third)
new_first = Node(lst.value, new_second)
return new_first
Example usage:
>>> list_1 = Node(3, Node(1, Node(4, Node(2))))
>>> print(list_1)
3->1->4->2->None
>>> list_2 = reverse_linked_list(list_1)
>>> print(list_2)
2->4->1->3->None
>>> list_3 = swap_23_linked_list(list_2)
>>> print(list_3)
2->1->4->3->None

Categories