Changing characters and reversing chained lists. (python) - 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

Related

How do you populate values into a class in 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.

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

Combining linked lists iteratively

I'm trying to combine two linked lists iteratively, but what I have right now is giving me the reverse of the result. Is there a way to combine the lists in the correct order without having to reverse if after the result list is created?
class Link:
empty = ()
def __init__(self, first, rest=empty):
assert rest is Link.empty or isinstance(rest, Link)
self.first = first
self.rest = rest
def __add__(self, lst):
"""
>>>s = Link(1, Link(2))
>>>s + Link(3,Link(4))
Link(1,Link(2,Link(3,Link(4))))
"""
result = Link.empty
while self is not Link.empty:
result = Link(self.first,result)
self = self.rest
while lst is not Link.empty:
result = Link(lst.first, result)
lst = lst.rest
return result
Conceptually, to combine two linked lists, all you need to do is find the tail of the first list, and connect it with the head of the second list, and then return the head of the first list. The major problem with the current code is that you do not keep around the head of the first list.
I'm assuming that you want the __add__ method to create a copy made up of self followed by lst, so simply create copies of the Links from self first and then lst and attach them as you iterate. Like so:
def __add__(self, lst):
result = Link(self.first)
cur = result
self = self.rest
# Copy our list
while self is not Link.empty:
cur.rest = Link(self.first)
cur = cur.rest
self = self.rest
# Copy and connect the Links in lst
while lst is not Link.empty:
cur.rest = Link(lst.first)
cur = cur.rest
lst = lst.rest
return result
To diagnose what's wrong with the current code, consider stepping through with an example. Assume self is Link(1,Link(2)).
result = Link.empty
while self is not Link.empty:
result = Link(self.first,result)
What's result now?
Link(self.first,result)
is Link(1, Link.empty)
self = self.rest
Now self is Link(2,())
result = Link(self.first,result)
What's result now?
Link(self.first,result)
is Link(2, Link(1, Link.empty))
Oops. Found the problem; you are connecting the links in reverse.
Avoid changing self, find the end of the first list, and add the second list to it.
def __add__(self, lst):
current = self
while current.rest != self.empty:
current = current.rest
current.rest = lst
return self
Or, if you prefer to return a new linked list:
def __add__(self, lst):
new_list = Link(self.first)
new_link = new_list
current = self
while current.rest != self.empty:
new_link.rest = Link(current.first)
new_link = new_link.rest
current = current.rest
current = lst
while current != self.empty:
new_link.rest = Link(current.first)
new_link = new_link.rest
current = current.rest
return new_list
Note: this will make references to each Link.first value (not independent copies).

Linked List Operations

Hello I need help trying to figure out these three functions. I am very new to python.
Assignment:
createList(srcSeq) - creates a linked list from the values
contained in the srcSeq sequence structure and returns the head
reference of the new linked list. The values will be added one at a
time by prepending them to the linked list. myValues = [5, 12, 82,
32, 20] myList = createList(myValues)
size(theList) - given the
head reference (theList), returns the number of elements in the
linked list.
printList(theList) - given the head reference
(theList), prints the values in the linked list from front to back
all on one line with the values separated by commas.
valueAt(theList, index) - returns the value contained in the node at
the given index position where the first value is at position 0, the
second at position 1 and so on. If index is out of range, return
None.
append(theList, value) - appends a new value to the end of
the linked list. Assume the list contains at least one node.
concat(listA, listB) - joins or concatenates two linked lists by
linking the last node of listA to the first node of listB.
split(theList) - given the head reference (theList), splits the
linked list in half to create two smaller linked lists. The head
reference of the linked list created from the second half of the list
is returned. Assume the list contains at least one node. If there is
an odd number of nodes in the linked list, the extra node can be
placed in either of the two new lists.
For the append, concat, do I simply just do. I do not know how to do the split method:
def append (theList, value):
current = self.head
while current.self.next != None:
current = self.next
current.newnode
def concat(listA, listB):
if listA.tail == None:
listA.head = listB.head
else:
listA.tail.next = listB.head
elif listB.head != None:
listA.tail = listB.tail
My Entire Code:
def createList( self ):
self.head = None
temp = ListNode( value )
self.next = newnext
temp.self.next(self.head)
self.head = temp
return self.head
def size( theList ):
current = self.head
count = 0
while current != None:
count = count + 1
current = current.self.next
return count
def printList( theList ):
node = self.head
while node:
print self.value
node = self.next
def valueAt( theList, index ):
current = head
count = 0
while current != None:
if count == index:
return current
def append( theList, value ):
current = self.head
while current.self.next != None:
current = self.next
current.newnode
def concat( listA, listB ):
if listA.tail == None:
listA.head = listB.head
else:
listA.tail.next = listB.head
elif listB.head != None:
listA.tail = listB.tail
def split( theList ):
pass
I think you problem is under-specified. but with what we have :
Splitting a singly linked list:
def split( head ):
middle = head
current = head
index = 0
while current.next != None:
if index % 2:
middle = middle.next
current = current.next
index += 1
result = middle.next
middle.next = None
return result
But to be honest, there is a lot more wrong with what you have so far.
If those lists were Python lists the solution would be really simple:
def split(a):
return a[:len(a)/2], a[len(a)/2:]
And now some explanation :) :
The function returns a tuple of two lists, where each list is one half of the supplied list a.
What I use above is called slicing and you can think of the colon character as of the word until. You can supply two _arguments beginning and end separated by that semicolon.
Example time!
a = [1,2,3,4,5]
a[:2] == [1,2]
a[2:] == [3,4,5]
a[1:3] == [2,3,4]
a[2,-2] == [3]
a[-3,-2] == [3,4]
Isn't slicing great? And it comes for free! One extra trick, if you want to make a copy of a list you can do that with slicing too!
b = a[:]
Boom, done! :)
There is more to slicing, you can have two colons, but that's a story for another time.
PS:
Out of curiosity I did your homework :)
class Node:
def __init__(self, data):
self.data = data
self.next = None
def __str__(self, *args, **kwargs):
return str(self.data)
def create_list(iterable):
next_node = current_node = None
for item in iterable:
current_node = Node(item)
current_node.next = next_node
next_node = current_node
return current_node
def size(head):
count = 0
while head:
head = head.next
count += 1
return count
def print_list(head):
while head:
print(head, end="")
if head.next:
print(" > ", end="")
head = head.next
print(flush=True)
pass
def value_at(head, index):
while (head):
if index < 1:
return head
index -= 1
head = head.next
return None
def append(head, value):
while head:
if not head.next:
head.next = Node(value)
return
head = head.next
def concat(headA, headB):
while headA:
if not headA.next:
headA.next = headB
return
headA = headA.next
def split(head):
center = head
index = 0
while head:
if index % 2:
center = center.next
head = head.next
index += 1
headB = center.next
center.next = None
return headB
def main():
a = create_list([1, 2, 3, 4, 5, 6, 7, 8, 9])
print("Print list::")
print_list(a)
print("\nSize:")
print(size(a))
print("\nValue at:")
print("a[-1]: %d" % value_at(a, -1).data)
print("a[0]: %d" % value_at(a, 0).data)
print("a[1]: %d" % value_at(a, 1).data)
print("a[5]: %d" % value_at(a, 5).data)
print("a[8]: %d" % value_at(a, 8).data)
# print("value # 9 %d"% value_at(my_head,9).data)
print("\nAppend (10):")
print_list(a)
append(a, 10)
print_list(a)
print("\nConcat a, b:")
print_list(a)
b = create_list([11, 12, 13])
print_list(b)
concat(a, b)
print_list(a)
print("\nSplit:")
print_list(a)
print("..into..")
b = split(a)
print_list(a)
print("Size a: %d" % size(a))
print_list(b)
print("Size b: %d" % size(b))
if __name__ == "__main__":
main()

Using single linked lists, how to swap nodes in python?

Currently, I've been trying to rearrange a linked list based on my main function switch(myList,index).
def createList(plist):
linkedList = None
# goes backwards, adding each element to the beginning
# of the list.
for index in range(len(plist)-1, -1, -1):
linkedList = insertValueHead(linkedList, plist[index])
return linkedList
def insertValueHead(linkedList, value):
newnode = {}
newnode["data"] = value
#set the next pointer of this new node to the head of the list, linkedList
#newnode is now the head of the list
newnode["next"] = linkedList
return newnode
def listString(linkedList):
ptr = linkedList
str1 = ''
while ptr != None:
str1 += str(ptr['data'])
ptr = ptr['next']
if ptr != None:
str1 += "->"
str1 = str1
return str1
def switch(j, i):
head = j
currentItem = j[0] # The head again
prevItem = 1 # The item that links to tempItem
for x in range(i): # Find the item to swap
prevItem = currentItem
currentItem = currentItem['next']
currentItem = currentItem['next']
temp = currentItem['next']
currentItem['next'] = head['next']
head['next'] = prevItem['next']
prevItem['next'] = temp
def testSwitch():
#test code to ensure that switch() is working correctly.
myList = createList([10, 20, 30, 40, 50, 60])
print "The initial list", listString(myList)
myList = switch(myList, 2)
print "Switching the 1 and the 2. Resulting list is ", listString(myList)
testSwitch()
This should yield a list with swapped elements. However, when I run it this is the output:
The initial list 10->20->30->40->50->60
Switching the 1 and the 2. Resulting list is
This is then followed by the error:
currentItem = currentItem['next']
TypeError: list indices must be integers, not str
What am I doing wrong? I can't seem to figure it out...
The simply-linked list is not a very useful construct, if you need to support switch operation. On a doubly linked list, if the nodes have the pointers forward and backward, then it is very easy, but on singly linked list you need to scan the list at least once. Also, your code is so messy that no one can really debug it. Thus
use class-based lists instead having items of a Node subclass, say.
for switch operation you seriously want to have doubly linked list.
Maybe use the linux linked list convention, where the ends are a list node too
Something like
class Node(object):
prev = None
next = None
class List(object):
def __init__(self):
self.head = self
self.tail = self
self.prev = self
self.next = self
self.nil = self
def insert_head(self, node):
node.next = self.head.next
self.head.next.prev = node
node.prev = self.head
self.head.next = node
def __iter__(self):
current = self.head.next
while current != self.nil:
yield current
current = current.next
def __str__(self): # the "list_string" op
items = []
return ' -> '.join(map(str, self))
class TestNode(Node):
def __init__(self, value):
self.value = value
def __repr__(self):
return repr(self.value)
list = List()
list.insert_head(TestNode('a'))
list.insert_head(TestNode('b'))
print(list)
Your indentation isn't proper, that's why you are getting the issue.
def switch(j, i):
head = j
currentItem = j[0] # The head again
prevItem = 1 # The item that links to tempItem
for x in range(i): # Find the item to swap
prevItem = currentItem
currentItem = currentItem['next']
currentItem = currentItem['next']
temp = currentItem['next']
currentItem['next'] = head['next']
head['next'] = prevItem['next']
prevItem['next'] = temp
Give an indent of four spaces inside a function or a loop. You can't assign j[0] to current item as it's a dict.

Categories