Add two numbers
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Loop through both, add values to list, create a list to int and add them, then create a linked list from the values is brute.
Time: Linear O(max(n1, n2))
Space: Linear O(max(n1, n2))
class Solution:
Find the intersection of linked list
You are given two singly linked lists. The lists intersect at some node. Find, and return the node. Note: the lists are non-cyclical.
Example:
A = 1 -> 2 -> 3 -> 4 B = 6 -> 3 -> 4
time: O (n1+n2)
space: O 1, we do not store any new values, we only change the head pointer of n1 or n2
def get_length(self, node):
def optimal(self, n1, n2):
Consecutive nodes sum to 0
Hi, here’s your problem today. This problem was recently asked by Uber:
Given a linked list of integers, remove all consecutive nodes that sum up to 0.
Example:
Input: 10 -> 5 -> -3 -> -3 -> 1 -> 4 -> -4
Output: 10
The consecutive nodes 5 -> -3 -> -3 -> 1 sums up to 0 so that sequence should be removed. 4 -> -4 also sums up to 0 too so that sequence should also be removed.
time: O(n), 2n because we loop through the linked list twice
space: O(n), worst-case we store all the values in the map
class Solution:
list strategies for linked lists
merge two sorted lists
Merge two sorted linked lists and return it as a sorted list. The list should be made by splicing together the nodes of the first two lists.
brute force is recursive, it will take O(n+m) time and space because of the recursive calls
time: O(n+m), we traverse both ll’s fully
space: constant
Linked list cycle
Given head, the head of a linked list, determine if the linked list has a cycle in it.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail’s next pointer is connected to. Note that pos is not passed as a parameter.
Return true if there is a cycle in the linked list. Otherwise, return false
brute is to use a hashmap, but you can reduce the space complexity
——–return False
time: O(2n), if it’s not cyclic it is just N, if it is it would be 2n to account for the slow iterations catching up with the fast ones. thinking about a fast/slow runner, the slow run would make 2 laps before they meet
space: constant, we create no new objects
class Solution:
Remove Kth element
Given the head of a linked list, remove the nth node from the end of the list and return its head.
brute force is to calculate length of list with 1 pass, create the current=dummy=node(0, head), then subtract length-index to figure out when we stop traversing the list to delete the node. This takes at most 2 passes
time: linear, 1 pass, 2 pointers
space, constant
class Solution:
swap nodes in pairs
Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem without modifying the values in the list’s nodes (i.e., only nodes themselves may be changed.)
time: O(n), linear,
space: recursive is linear bc of recursive space, iterative is constant space
class Solution:
Palindrome linked list
determine if a linked list is a palindrome
1, 2, 2, 1
1, 2, 3, 2, 1
1, 1, 1, 2, 3, 1,
time: O(n/2 + n/2 + n/2), we loop through half the node to get to the middle with slow, reverse slow, compare slow to current
space: constant, we do not create any additional objects
class Palindrome(object):
Convert Binary Search Tree to Sorted Doubly Linked List
Convert a Binary Search Tree to a sorted Circular Doubly-Linked List in place.
You can think of the left and right pointers as synonymous to the predecessor and successor pointers in a doubly-linked list. For a circular doubly linked list, the predecessor of the first element is the last element, and the successor of the last element is the first element.
We want to do the transformation in place. After the transformation, the left pointer of the tree node should point to its predecessor, and the right pointer should point to its successor. You should return the pointer to the smallest element of the linked list.
brute is to do inorder traversal to create a list, create the circular dll with that list
time: O(n), we traverse the whole tree and create the dll in 1 pass
space: O(N) the recursion depth, Log(n) if it is balanced
class Node:
class Solution:
create a circular doubly linked list
class Node:
# Function to insert at the end def insertEnd(value) : ----global start ---- ----# If the list is empty, create a ----# single node circular and doubly list ----if (start == None) :
—-# If list is not empty
# Function to insert Node at the beginning # of the List, def insertBegin( value) : ----global start ---- ----# Pointer points to last Node ----last = (start).prev
# Function to insert node with value as value1. # The new node is inserted after the node with # with value2 def insertAfter(value1, value2) : ----global start ----new_node = Node(0) ----new_node.data = value1 # Inserting the data
def display() :
copy list with random pointer
A linked list of length n is given such that each node contains an additional random pointer, which could point to any node in the list, or null.
Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes, where each new node has its value set to the value of its corresponding original node. Both the next and random pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state. None of the pointers in the new list should point to nodes in the original list.
For example, if there are two nodes X and Y in the original list, where X.random –> Y, then for the corresponding two nodes x and y in the copied list, x.random –> y.
Return the head of the copied linked list.
The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:
val: an integer representing Node.val
random_index: the index of the node (range from 0 to n-1) that the random pointer points to, or null if it does not point to any node.
Your code will only be given the head of the original linked list.
iterative/recursive brute force involve a hashmap with the key being the real node and the value being the copy node. Check if the node already exists, if it does return it, else make one and return it. Both are linear time and space. For recursive problem remember to watch for cycles and think of it like a binary tree
Questions: Can you modify the original input? will the input always be of class Node? can the random pointers point to the same node? will there be nodes with duplicate values?
time: O(n), we loop through the original list and copy list
space: constant,
class Solution:
Design a linked list
Design your implementation of the linked list. You can choose to use a singly or doubly linked list.
A node in a singly linked list should have two attributes: val and next. val is the value of the current node, and next is a pointer/reference to the next node.
If you want to use the doubly linked list, you will need one more attribute prev to indicate the previous node in the linked list. Assume all nodes in the linked list are 0-indexed.
Implement the MyLinkedList class:
MyLinkedList() Initializes the MyLinkedList object. int get(int index) Get the value of the indexth node in the linked list. If the index is invalid, return -1. void addAtHead(int val) Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. void addAtTail(int val) Append a node of value val as the last element of the linked list. void addAtIndex(int index, int val) Add a node of value val before the indexth node in the linked list. If index equals the length of the linked list, the node will be appended to the end of the linked list. If index is greater than the length, the node will not be inserted. void deleteAtIndex(int index) Delete the indexth node in the linked list, if the index is valid.
add at head is constant, the rest are linear time.
class ListNode:
class MyLinkedList:
class MyLinkedList:
Design a doubly linked list
Design your implementation of the linked list. You can choose to use a singly or doubly linked list.
A node in a singly linked list should have two attributes: val and next. val is the value of the current node, and next is a pointer/reference to the next node.
If you want to use the doubly linked list, you will need one more attribute prev to indicate the previous node in the linked list. Assume all nodes in the linked list are 0-indexed.
Implement the MyLinkedList class:
MyLinkedList() Initializes the MyLinkedList object. int get(int index) Get the value of the indexth node in the linked list. If the index is invalid, return -1. void addAtHead(int val) Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. void addAtTail(int val) Append a node of value val as the last element of the linked list. void addAtIndex(int index, int val) Add a node of value val before the indexth node in the linked list. If index equals the length of the linked list, the node will be appended to the end of the linked list. If index is greater than the length, the node will not be inserted. void deleteAtIndex(int index) Delete the indexth node in the linked list, if the index is valid.
class ListNode:
class MyLinkedList:
linked list cycle 2
Given the head of a linked list, return the node where the cycle begins. If there is no cycle, return null.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail’s next pointer is connected to (0-indexed). It is -1 if there is no cycle. Note that pos is not passed as a parameter.
Do not modify the linked list.
brute force is to use a hashmap
time: O(n). finding the cycle takes linear time, a proof shows it is F + C - h where F are the nodes not in the cycle and C are nodes in the cycle. The second part will take linear time aswell
space: constant
class Solution:
remove linked list elements
Given the head of a linked list and an integer val, remove all the nodes of the linked list that has Node.val == val, and return the new head.
class Solution:
flatten a multi-level doubly linked list
You are given a doubly linked list, which contains nodes that have a next pointer, a previous pointer, and an additional child pointer. This child pointer may or may not point to a separate doubly linked list, also containing these special nodes. These child lists may have one or more children of their own, and so on, to produce a multilevel data structure as shown in the example below.
Given the head of the first level of the list, flatten the list so that all the nodes appear in a single-level, doubly linked list. Let curr be a node with a child list. The nodes in the child list should appear after curr and before curr.next in the flattened list.
Return the head of the flattened list. The nodes in the list must have all of their child pointers set to null.
Example 1:
Input: head = [1,2,3,4,5,6,null,null,null,7,8,9,10,null,null,11,12]
Output: [1,2,3,7,8,11,12,9,10,4,5,6]
Explanation: The multilevel linked list in the input is shown.
After flattening the multilevel linked list it becomes:
time: O(n), you go through the entire list once
space: O(n), worst case each node has a child element and you have N recursive space
class Solution:
insert into a sorted circular linked list
Given a Circular Linked List node, which is sorted in ascending order, write a function to insert a value insertVal into the list such that it remains a sorted circular list. The given node can be a reference to any single node in the list and may not necessarily be the smallest value in the circular list.
If there are multiple suitable places for insertion, you may choose any place to insert the new value. After the insertion, the circular list should remain sorted.
If the list is empty (i.e., the given node is null), you should create a new single circular list and return the reference to that single node. Otherwise, you should return the originally given node.
time: O(n), we loop once at most!
space: O(1), no new data structures
class Solution:
rotate linked list
Given the head of a linked list, rotate the list to the right by k places.
Example 1:
Input: head = [1,2,3,4,5], k = 2
Output: [4,5,1,2,3]
brute force would be making a hashmap or array, then doing something similar to reverse array
time: O(n), we rotate through the list once, then again bc of the rotations
space: O(1)
class Solution:
You are given an array of k linked-lists lists, each linked-list is sorted in ascending order.
Merge all the linked-lists into one sorted linked-list and return it.
Example 1:
Input: lists = [[1,4,5],[1,3,4],[2,6]] Output: [1,1,2,3,4,4,5,6] Explanation: The linked-lists are: [ 1->4->5, 1->3->4, 2->6 ] merging them into one sorted list: 1->1->2->3->4->4->5->6
time: O(n * logk) bc we merge the N nodes log(k) times where k is the len of lists
space: O(1), a slight improvement over my priority queue method
class Solution:
Custom solution, space is not truly optimal.
time: O(n log K), where K is the number of linked lists and N is the total nodes. The heapq is kept at k length bc we never add more than k values to it and we do it N times.
space: O(K) where k is the number of linked lists
import heapq class Solution: ----def mergeKLists(self, lists): --------if not lists: ------------return None -------- --------dummy_head = cur = ListNode(-1) -------- --------queue = [] --------for head in lists: ------------if head: ----------------heapq.heappush(queue, Comparator(head.val, head, head.next)) -------- --------while queue: ------------comparator = heapq.heappop(queue) ------------val, node, _next = comparator.val, comparator.cur, comparator._next ------------cur.next = node ------------cur = cur.next ------------if _next: ----------------heapq.heappush(queue, Comparator(_next.val, _next, _next.next)) ------------ --------return dummy_head.next ---- class Comparator: ----def \_\_init\_\_(self, val, cur, _next): --------self.val = val --------self.cur = cur --------self._next = _next -------- ----def \_\_lt\_\_(self, y): --------if self.val == y.val: ------------return True --------else: ------------return self.val < y.val