Removing all repeated elements in a linked list - python

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
Example 1:
Input: 1->2->3->3->4->4->5
Output: 1->2->5
Example 2:
Input: 1->1->1->2->3
Output: 2->3
I have tried and succeeded in my code with most cases, the only case I am missing is when the list ends in duplicates and there are non duplicates throughout.
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
first = head
if first is None:
return []
second = head.next
if second is None:
return first
first.next = second
if first.val == first.next.val:
while first.val == first.next.val:
if first.next.next is None:
return []
first = first.next
return self.deleteDuplicates(first.next)
else:
first.next = self.deleteDuplicates(first.next)
return first
The error I get for [1,2,3,4,4] is "AttributeError: 'list' object has no attribute 'val'".

You can do this in $O(n)$ time and $O(n)$ space (worst case) by just keeping track of what you've seen so far, assuming your data is hashable.
from collections import defaultdict
def mark_duplicates(current_node, seen_so_far):
next = current_node.next
seen_so_far[current_node.data] += 1
if next is None: return seen_so_far
return mark_duplicates(next, seen_so_far)
def remove_duplicates(current_node, seen):
next = current_node.next
prev = current_node.prev
if seen[current_node.data] > 1:
if prev is not None: prev.next = next
if next is not None: next.prev = prev
# No need to delete current_node, the GC will do it
if next is not None: remove_duplicates(next, seen)
notes = mark_duplicates(head_of_list, defaultdict(int))
remove_duplicates(head_of_list, notes)
A defaultdict(int) is just a dictionary that'll return 0 when you try to access a key that doesn't exist. So this counts how many times each value appears, then removes everything that's shown up more than once.

The code works fine, I just needed to change return [] to simply "return" as [] wasn't being recognized as an empty linked list, but rather just an empty list. Thanks to Devesh Kumar Singh for recognizing this error, but he didn't post it as an answer so I am posting it on his behalf.

Related

Linked List and array

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

what will I need to return for list and do I need code for edge case duplicate?

I have the following ListNode class:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
I wrote the following code with the aim of removing any duplicates from a linked list:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if head == None:
return None
if head.next == None:
return head
curr = head
nex = head.next
while nex:
if head.val == nex.val:
curr.next = nex.next
curr = nex.next
nex = curr.next
Questions:
What do I return at the end? Is it 'head' or 'curr' or something else? And why?- I know that I want the output to be a linked list of the input but with duplicates removed; so does it make sense to return the head of the linked list? But when I do this, I don't quite get the expected results, namely [1,1,2,2,3,3] -> [1,2,3,3]; which leads me to my next question...
Do I need to write an edge case for when there is a duplicate right at the end of the linked list? As I don't believe my code below deals with this -- am I right?
I'll assume that your list is always sorted, so that any duplicates are always sitting next to each other in the list.
There are two issues in your while loop:
You should compare the values from the two adjacent nodes, but your code is always comparing the next value with the head node's value. So change:
if head.val == nex.val:
to
if curr.val == nex.val:
Your code is skipping nodes by doing curr = nex.next. This means that curr will never be nex. This also has as effect that the next statement may be an invalid reference, as curr might be None. So change:
curr = nex.next
to
curr = nex
When you detect a duplicate, only nex should move to the next node. curr should stay where it is, as it may have more than one duplicate to deal with. So the above assignment to curr should only happen when you don't have a duplicate.
The corrected while loop is as follows:
while nex:
if curr.val == nex.val:
curr.next = nex.next
else:
curr = nex
nex = curr.next
What to return
Since your function seems to be designed to return a ListNode, just make sure to always return head. So add that statement also after the while loop.
In my opinion it shouldn't have been necessary for this function to return the head node, since the value of head will never change by this function. So the caller already knows the value.
NB: you don't need to deal specifically with this case:
if head.next == None:
return head
This case will just mean that the while loop will not have a single iteration. As said above, just add a return statement at the very end of the function, and then you can drop the above if block:
return head

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

Python:Moving through linked list 'next'

I'm working through Cracking the Coding Interview 6th ed and am unsure of their definition of 'next'
Their code defining "Linked List" can be found here. I'm trying out the second exercise, which is to find the kth from the end element of a random linked list.
My code:
from LinkedList import LinkedList
def kth_to_last(ll, k):
num_seen = 0
length_list = count_length(ll)
val = ll.head
# ISSUE IS HERE
while val.next != None:
print 'hi'
val.next = val.next.next
"""
while num_seen < (length_list - k):
val = val.next
num_seen += 1
"""
return val.next
# Counts length of LL
def count_length(ll):
val = ll.head
count = 1
while val.next != None:
count += 1
val.next = val.next.next
return count
ll = LinkedList()
ll.generate(10, 0, 99)
print(ll)
kth_to_last(ll, 3)
It's counting through the list just fine, but for the first definition, I can't get it to move through the linked list (it won't print 'hi' at all).
I plan to do something like I have commented out (they also have 'tail' defined so I might try that out), but I'm confused why I can move through the list just fine within 'count_length,' but then I can't seem to move through it within 'kth_to_last'?
Edit: To clarify, if I print val.next within 'kth_to_last' it has a value of 'None'
Edit2:
If I comment out the "count_length," the next proceeds just fine. Could someone explain to me why calling this function alters next. Has it stuck me at the end of the list?
My code:
def kth_to_last(ll, k):
"""
num_seen = 0
length_list = count_length(ll)
"""
# Start at head
val = ll.head
while val.next != None:
print val.next
val = val.next
This prints the list just fine
You should do val = val.next instead of val.next = val.next.next. The way you're doing it, the list will be truncated to a single element when you call count_length. Because you do count_length at the top of kth_to_last, by the time you get around to walking your list (where your 'hi' is), the list has already been reduced to a single node.
Remember, a linked list is a structure where each node's next property is a pointer to the next node. Your code is modifying the value of next, which is changing the structure of your linked list.
When you process a linked list (in count_length, or in kth_to_last), what you want to do is point yourself at each node in turn. You're not trying to modify the nodes themselves, so you won't assign to their value or next attributes. The way to do this is to change what your pointer (val) is pointing at, and the thing that you want it to point at next is the next node along. Therefore:
val = ll.head
while val is not None:
# do something with val here
val = val.next

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