Rotate a linked list k times (Python) - python

While practicing for my final in Python programming I ran into this question "def rotaten" of rotating k times. The problem says that k can range from 0 to any positive integer number (even greater than list size, if k < 0 raise ValueError
and it must execute in O( (n-k)%n ) where n is the length of the list. It also has the following warnings:
WARNING: DO NOT call .rotate() k times !!!!
WARNING: DO NOT try to convert whole linked list to a python list
WARNING: DO NOT swap node data or create nodes
The problem is that I'm not understanding the solution given. Is there an easier way to solve this problem? Thank you in advance
class Node:
def __init__(self,initdata):
self._data = initdata
self._next = None
def get_data(self):
return self._data
def get_next(self):
return self._next
def set_data(self,newdata):
self._data = newdata
def set_next(self,newnext):
self._next = newnext
class LinkedList:
def rotaten(self, k):
if k < 0:
raise ValueError
if self._size > 1:
m = k % self._size
if m > 0 and m < self._size:
current = self._head
for i in range(self._size - m - 1):
current = current.get_next()
chain_b = current.get_next()
old_head = self._head
old_last = self._last
self._last = current
self._last.set_next(None)
self._head = chain_b
old_last.set_next(old_head)

The easiest ways are forbidden
warning forbids implementing the singular rotation, then calling it repeatedly
warning forbids using native python structure - python has list built-in in basic collections list(), which can be then transformed to a deque, which can then be rotated by popping from the end and inserting the same node to the beginning.
warning is preventing you from making your life easier by creating some other nodes or worse - copying data. (copying data from one node to another would remove any advantage you had from storing the data into the lists in the first place)
The example solution is basically this:
Take the current first node(head of the list) and the tail node which is stored in the List structure. (the bookkeeping of the example list consists of holding the head and tail, the rest is done in the nodes themselves)
Find the k-th node - so that you rotate the whole list at once. This is where the list needs to be cut.
Add the last node as the new head, doing all the necessary reference-linking and unlinking. (Which is I guess the point of this question - to test if you understand the references. In C these would be pointers, python has the references implicitly.)
So as far as the linked lists go, this is the most straightforward solution with the requested O((n-k)%n) complexity.
Good luck with your pointers :-).

Related

How to Initialize a Min Heap?

I'm trying to figure out how I can initialize a min heap using an array. So far my function looks like this:
def start_heap(self,n):
# None positions to be filled with Nodes
arr = [none][] * n
for i in arr:
heapify(i)
def heapify(self):
start = self.parent(len(self) - 1) # Start at parent of last leaf
for j in range(start, -1, -1): # going to and including the root.
self.heapify_down(j)
def heapify_down(self, i):
n = len(self._pq)
left, right = self.left(i), self.right(i)
if left < n:
child = left
if right < n and self.pq[right] < self.pq[left]:
child = right
if self.pq[child] < self.pq[i]:
self.swap(i, child)
self.heapify_down(child)
Heapify Down Pseudocode:
Heapify-down(H,i): Let n = length(H) If 2i>n then
Terminate with H unchanged Else if 2i<n then
Let left=2i, and right=2i+1
Let j be the index that minimizes key[H[left]] and key[H[right]] Else if 2i=n then
Let j=2i Endif
If key[H[j]] < key[H[i]] then
swap the array entries H[i] and H[j] Heapify-down(H , j)
Endif
I'm going to build a simple node class that just holds data but I'm not sure how to actually get the start_heap function working. Keep in mind n is the maximum number of elements that can be stored.
Some remarks on the code you provided (not on the code you didn't provide):
arr is a local variable, so whatever you do with it, once the function returns, that arr will be out of scope... and lost. You need an attribute or else subclass list
It is not common practice to "allocate" the array and fill it with None. In Python lists are dynamic, so you don't need to reserve slots ahead of time. You just need an empty list to start with.
There is no need to call heapify when the heap is empty.
There is certainly no need to call heapify many times in a loop. All the logic for heapifying is already present in that method, so no need to call it on each index individually. But as stated in the previous point: no need to call it on an empty list -- there is nothing to move.
So the correction is quite basic:
def start_heap(self, max_size):
self.max_size = max_size
self._pq = []
Then, in many of your other methods, you will have to work with self._pq and self.max_size.
For instance, it could have a method that indicates whether the heap is full:
def is_full(self):
return len(self._pq) >= self.max_size
If you have an add method, it would first check if there is still room:
def add(self, node):
if is_full(self):
raise ValueError("Cannot add value to the heap: it is full")
# ... rest of your code ...

How to interact head of linkedlist outside the LinkedList class in Python?

I am trying to solve the following problem on algoexpert:
Shift Linked List
Write a function that takes in the head of a Singly Linked List and an integer
k, shifts the list in place (i.e., doesn't create a brand new
list) by k positions, and returns its new head.
Shifting a Linked List means moving its nodes forward or backward and wrapping
them around the list where appropriate. For example, shifting a Linked List
forward by one position would make its tail become the new head of the linked
list.
Whether nodes are moved forward or backward is determined by whether
k is positive or negative.
Each LinkedList node has an integer value as well as
a next node pointing to the next node in the list or to
None / null if it's the tail of the list.
You can assume that the input Linked List will always have at least one node;
in other words, the head will never be None / null.
Sample Input
head = 0 -> 1 -> 2 -> 3 -> 4 -> 5 // the head node with value 0
k = 2
Sample Output
4 -> 5 -> 0 -> 1 -> 2 -> 3 // the new head node with value 4
The outline that the problem gives for the code is the following:
class LinkedList:
def __init__(self, value):
self.value = value
self.next = None
def shiftLinkedList(head, k):
#Write your code here.
pass
I suppose my background on linked list is very limited because from every resource I've read on linked lists, the general outline for it requires the node class and to have all the methods for rotating or shifting inside the LinkedList class.
I assume the head parameter for the function is going to be an integer that denotes the position of the list but how do I refer the head back to the original list? I already have the code written in my Thonny editor but I wrote the function inside the LinkedList class and simply called for it after making my list.
For example:
class Node:
def __init__self(data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def push(self, newhead):
newnode = Node(new_data)
newnode.next = self.head
self.head = newnode
list1 = LinkedList()
list1.head = Node(1)
e2 = 2
e3 = 3
list1.head.next = e2
e2.next = e3
Only once I've established my linked list can I create a method inside the class to shift or rotate it. Or am I wrong?
I tried creating a function the way the algo wanted, but I am still stuck. I think what I am really confused about is whether the argument head is an integer or a LinkedList?
Here is my complete attempt:
class Node:
def __init__(self, data):
self.data = data #assign data
self.next = None #initialize next as null
class LinkedList:
#function to initalize the linked list object
def __init__(self):
self.head = None
def printList(self):
temp = self.head
while(temp):
print(temp.data)
temp = temp.next
def moveToFront(self):
tmp = self.head
sec_last = None
if not tmp or not tmp.next:
return
while tmp and tmp.next:
sec_last = tmp
tmp = tmp.next
sec_last.next = None
tmp.next = self.head
self.head = tmp
def shiftList(head, k):
if not head:
return
tmp = head
length = 1
while(temp.next != None):
tmp = tmp.next
length += 1
if(k>length):
k = k%length
k = length - k
if(k==0 or k==length):
return head
current = head
cmt = 1
while(cmt < k and current != None):
current = current.next
cmt += 1
if(current==None):
return head
kthnode = current
tmp.next = head
head = kthnode.next
kthnode.next = None
return head
I assume the head parameter for the function is going to be an integer that denotes the position of the list
No, the head of a list is a LinkedList instance. So head.value is the value of the first node in the list, and head.next is a reference to the second node in the list.
In your attempt you have changed the definition of LinkedList from the original, and created another class, called Node, which really is what LinkedList is supposed to be (except that you call a property data instead of value). It is understandable that you did this, as you wanted to have a kind of container class for the whole linked list, and reserve a separate class Node for what concerns a single node in that list. But this code challenge does not work with such a container class.
It just works with one class that represents a node, but through its next member the whole list is inferred from it. Moreover, they want the function to return a reference to the node that has become the head of the list once the shifting has completed. This is a different way of working than with a container class, in which you would mutate the head member, and would not return anything: the caller would just access the list through the modified head member.
So, what you intended to do is not inherently wrong, it just is not the data structure that this code challenge is working with. You should go with it.
what I am really confused about is whether the argument 'head' is an integer or a linkedlist
It is a node, but the list is inferred from it. It can be a bit confusing that they call their class LinkedList and not Node, but it is a matter of how you look at it.
So here is how you could solve it:
First find out what the last node is in the list. For this you will have to start from the head (you have nothing else) and step through the list until you bump into its end. Also maintain a counter so that at the end you know how many nodes there are in the list.
Then create a link from that tail node to the head node, so that the list now becomes circular: it has no end anymore
Find out which node comes k steps before the tail node in this cyclic list. As it is not possible to walk backwards in a list, you should actually walk size-k steps forward, and so you need the size of the list which you determined in the first step.
The node after that found node should become the head node.
Make that node itself the new tail node: break the link it has with the node after it (the new head).
Return the new head reference
One more thing should be done to protect this code against huge values for k. Let's say the list has 6 elements, and k is 600, then of course it makes no sense to run over the cyclic list 600 times, as we can predict that you'll end where you started! 600 is a multiple of 6... So to make this efficient, you need to reduce k to a number that is less than the size of the list. The formula for knowing how many steps forward you need to take is -k % size.
Here is the implementation of this idea:
def shiftLinkedList(head, k):
if not head:
return # Nothing to do
# Determine size of the list, and its tail node
size = 1
tail = head
while tail.next:
size += 1
tail = tail.next
# Temporarily make the list cyclic
tail.next = head
# Find out where to cut the cycle
for _ in range(-k % size):
tail = tail.next
head = tail.next
# Cut the cycle
tail.next = None
return head

How does the referencing work in python and how to create a sperate copy of linkedlist to compare with original linkedlist

class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
regularListHead = ListNode(-1)
regularListHead.next = head
reverseListHead = head
reverseListPrev = None
reverseListCurrent = reverseListHead
while reverseListCurrent != None:
reverseListNext = reverseListCurrent.next
reverseListCurrent.next = reverseListPrev
reverseListPrev = reverseListCurrent
reverseListCurrent = reverseListNext
reverseListHead = reverseListPrev
a = regularListHead
In my code, I am trying to convert the original list to reversed list and compare both for checking palindrome but when I do the operations to reverse the reverselist then original list is also updated. I am new to python can anyone let me know why this is happening and what could be done to achieve what I want
You only create one new node. All the other nodes are the nodes of your original list, and you update their next properties so the list is reversed.
So if you want to have both the original and the reversed list, you'll have to have two lists, each having their own nodes:
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if head is None:
return
# Create reversed list
revHead = ListNode(head.val)
current = head.next
while current is not None:
revHead = ListNode(current.val, revHead)
current = current.next
# Compare original with the reversed one
while head is not None:
if head.val != revHead.val:
return False
head = head.next
revHead = revHead.next
return True
This is however not optimal: the comparison loop should only need to perform 𝑛/2 comparisons, not 𝑛.
You may even ask yourself why you would create a linked list for the reversed version: as it is only needed for the palindrome check, you might as well create a standard list, and then do the palindrome check with just that list, which is a piece of cake.
But more importantly, creating a new list (whether a linked list or normal "array" list) requires O(n) extra space. If you are interested in an algorithm for doing this without creating new nodes, then try to implement this:
Count the number of nodes in the list
Use that to identify the first node of the second half of the list. If the number of nodes is odd, let this be the node after the center node.
Apply an in-place list reversal algorithm on that second half. Now you have two shorter lists.
Compare the values in those two lists to see whether they are equal (ignore the center node if there was one). Remember the outcome (false or true)
Optionally repeat step 3 so the reversal is rolled back, and the list is back in its original state. (This is "nice" towards the caller of your function)
Return the result that was found in step 4.

Fastest way to prove linked list is circular ? in python [duplicate]

This question already has answers here:
Best algorithm to test if a linked list has a cycle
(12 answers)
Closed 9 years ago.
Could someone please let me know the best way to prove a linked list contains a loop?
I am using an algorithm with two pointer, one is moving slow with one steps and one is moving faster with two steps.
class Node(object):
def __init__(self, value, next=None):
self.next=next
self.value=value
def create_list():
last = Node(8)
head = Node(7, last)
head = Node(6, head)
head = Node(5, head)
head = Node(4, head)
head = Node(3, head)
head = Node(2, head)
head = Node(1, head)
last.next = head
return head
def is_circular(head):
slow = head
fast = head
while True:
slow = slow.next
fast = fast.next.next
print slow.value, fast.value
if slow.value == fast.value:
return True
elif slow is fast:
return False
if __name__ == "__main__":
node = create_list()
print is_circular(node)
A good algorithm is as follows, it may very well be the best. You do not need to copy the list or anything, like that, it can be done in constant space.
Take two pointers and set them to the beginning of the list.
Let one increment one node at a time and the other two nodes at a time.
If there is a loop at any point in the list, they will have to be pointing to the same node at some point (not including the starting point). Obviously if you reach the end of the list, there is no loop.
EDIT:
Your code, but slightly edited:
def is_circular(head):
slow = head
fast = head
while fast != None:
slow = slow.next
if fast.next != None:
fast = fast.next.next
else:
return False
if slow is fast:
return True
return False
Don't know about best, but simpliest I can think of is
>>> import json
>>> l = []
>>> l.append(l)
>>> json.dumps(l)
Traceback (most recent call last):
...
ValueError: Circular reference detected
I would test it just like in any other language:
Start traversing the list from the start, adding all visited elements into a data structure (e.g. a set) with fast insertion and lookup. If you hit the end of the list without seeing any element twice, the list is not circular. If you see an element twice, the list is circular.
If neither is true, the list is infinite. :-)
Here is way to do it:
Start from a node & store its pointer in variable
Start visiting next elements till end or the start node is revisited.
if end is reached then it is not circular else circular

Return tuple of list in recursion function

I am learning Python's recursion. I define a linked list where each node has item and next. I want to write a recursion to put odd and even number in a seperate set.
class LinkNode(object):
"""A node in a linked list."""
def __init__(self, item, next=None):
"""(LinkNode, object, LinkNode) -> NoneType
Initialize this node to store item and next.
"""
self.item = item
self.next = next
def odd_or_even(self):
"""(LinkNode) -> ([object], [object])
Return a pair of lists: (odd number, even number.
"""
if self is None:
return ([], [])
else:
if (self.item % 2 == 1):
odd_num = odd_num.append(self.item)
else:
even_num = even_num.append(self.item)
if self.next is not None:
self.next.odd_or_even()
return (odd_num, even_num)
When I run it, i got the following error:
File "C:\Program Files\Wing IDE 101 4.1\src\debug\tserver_sandbox.py", line 19, in odd_or_even
builtins.UnboundLocalError: local variable 'odd_num' referenced before assignment
Where should i initial odd_num, even_num so it won't be overwritten?
Thanks.
I think there are a few different approaches you could use.
One would be to use global variables. I don't really recommend this, but it is easy to understand, so I'm presenting it first:
even_num = [] # these should be at module level, but I'm not showing the class
odd_num = [] # so you'll have to imagine the indentation being correct
def odd_or_even(self):
"""(LinkNode) -> ([object], [object])
Return a pair of lists: (odd number, even number.
"""
if self.item % 2 == 1:
odd_num.append(self.item)
else:
even_num.append(self.item)
if self.next is not None:
self.next.odd_or_even()
The changes to the code are minor, mostly just removing return statements. I did take out the initial check for self being None, as that's never possible in a method (unless the caller tries very hard to make it happen). It's also worth noting that we do not attempt to assign to odd_num or even_num directly, as that would create a local variable, rather than accessing the global variables that already exist. The downside of this solution is that you can only call odd_or_even once and have it work properly. If you want to call it again (perhaps on another list) you need to reinitialize global variables.
Here's a better approach, which creates even and odd lists as local variables, and then returns them at the end. This is probably what you were aiming for in your code, but you were missing the step of adding the results of the recursive call onto the list.
def odd_or_even(self):
even_num = []
odd_num = []
if self.item % 2 == 1:
odd_num.append(self.item)
else:
even_num.append(self.item)
if self.next is not None:
next_even, next_odd = self.next.odd_or_even()
even_num.extend(next_even)
odd_num.extend(next_odd)
return even_num, odd_num
The problem with this code is that creating and extending lists is wasteful. On each level of the recursion, two new lists will be created, even though only one value is going to be handled at that level. A better approach can use just two lists total, for the whole recursive process:
def odd_or_even(self, lists=None):
if lists is not None:
even_num, odd_num = lists
else:
even_num = []
odd_num = []
if self.item % 2 == 1:
odd_num.append(self.item)
else:
even_num.append(self.item)
if self.next is not None:
return self.next.odd_or_even((even_num, odd_num))
else:
return even_num, odd_num
This is more efficient than the previous version, since it uses the same list on all levels of the recursion. In some other programming languages, this style of recursion, where all the work is done before the recursive call is run, is much more efficient than other kinds of recursion. This is because a compiler can optimize away the return step of the function (and just reuse the stack frame). However, Python doesn't do such "tail call optimization" (because it would mess up stack traces) so the benefits are not as big as they might be.
Another thing to think about: You could use your own linked-list class, rather than Python lists to hold the even and odd values. Both the second and third solutions I showed above could work, though the third would work most naturally if you were willing to have the even and odd values returned in reverse order.
if (self.item % 2 == 1):
odd_num = odd_num.append(self.item)
else:
even_num = even_num.append(self.item)
...
return (odd_num, even_num)
The above section of code sets the value of either odd_num or even_num, but not both. It then attempts to return both odd_num and even_num, which produces an error for one or the other. If you initialize both to None just before that if statement, you'll avoid the error that occurred. However, to make the semantics work, you may need to add another parameter to your function, namely the result from the previous level; in the recursive call, pass the just-computed odd_num or even_num down to the next level; then return the result of the next level down. However, it might be better to avoid recursion and instead have a loop that runs twice.

Categories

Resources