1. Linked List1.1 Delete/InsertLC237: Delete node in a linked listLC203: Remove linked list elementsLC83: Remove duplicates from sorted listLC82: Remove duplicates from sorted list II1.2 ReverseLC206: Reverse linked listLC92: Reverse linked list IILC24: Swap nodes in pairsLC25: Reverse nodes in k-group1.3 ArithmeticLC2: Add two numbersLC445: Add two numbers IILC369: Plus one linked list1.4 Fast/slow pointersLC141: Linked list cycleLC142: Linked list cycle IILC287: Find the duplicate numberLC19: Remove Nth node from end of listLC143: Reorder listLC160: Intersection of two linked listsLC234: Palindrome linked list1.5 SortLC148: Sort listLC21: Merge two sorted listsLC23: Merge k sorted listsLC350: Intersection of two arrays IILC147: Insertion sort listLC86: Partition listLC328: Odd even linked listLC61: Rotate list1.6 OthersLC379: Design phone directoryLC138: Copy list with random pointer2. List in C++ STL2.1 forward_list2.2 list3. Heap/Priority Queue4. Pointer/Dynamic Memory
Linked list questions: https://leetcode.com/tag/linked-list/
Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.
void deleteNode(ListNode* node){ if(node == nullptr) return; ListNode *p=node; while(p->next != nullptr) { p->val = p->next->val; if(p->next->next == nullptr) break; p = p->next; }//--while delete p->next; p->next = nullptr;}Remove all elements from a linked list of integers that have value val.
ListNode* removeElements(ListNode* head, int val) { if(head == nullptr) return head; ListNode* dummy = new ListNode(INT_MIN); dummy->next = head; ListNode *pre=dummy, *cur=head; while(cur != nullptr) { ListNode* next = cur->next; if(cur->val == val) { pre->next = cur->next; delete(cur); } else { pre = cur; } cur = next; }//--while head = dummy->next; delete(dummy); return head;}Given a sorted linked list, delete all duplicates such that each element appear only once.
ListNode* deleteDuplicates(ListNode* head) { if(head == nullptr) return head; ListNode* dummy = new ListNode(INT_MIN); dummy->next = head; ListNode *p = dummy; while(p!=nullptr && p->next!=nullptr) { int val = p->next->val; if(val != p->val) { data.insert(val); p = p->next; } else { //duplicate, remove delete(p->next); p->next = p->next->next; } }//--while return dummy->next; }Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
//looking forward further ListNode* deleteDuplicates(ListNode* head) { if(head == nullptr) return head; ListNode* dummy = new ListNode(INT_MIN); dummy->next = head; ListNode* p = dummy; while(p->next!=nullptr && p->next->next!=nullptr) { if(p->next->val == p->next->next->val) { //duplicate int mark = p->next->val; //mark the value ListNode* tmp = p->next; //keep removing while(tmp!=nullptr && tmp->val==mark) { delete(tmp); tmp = tmp->next; } p->next = tmp; } else { p = p->next; } }//--while return dummy->next; }Reverse a singly linked list.
//iterative, with new headListNode* reverseList(ListNode* head){ if(head == nullptr) return head; ListNode* p = head; ListNode* dummy = new ListNode(INT_MIN); while(p != nullptr) { ListNode* tmp = p->next; p->next = dummy->next; dummy->next = p; p = tmp; }//--while return dummy->next;} //iterative, without new headListNode* reverseList(ListNode* head){ if(head == nullptr) return head; ListNode* pre = nullptr; ListNode* p = head; while(p != nullptr){ ListNode* next = p->next; p->next = pre; pre = p; p = next; }//--while return pre;} //recursivevoid doReverse(ListNode* p, ListNode*& head){ if(p->next == nullptr){ head->next = p; return; } doReverse(p->next); ListNode* q = p->next; q->next = p; p->next = null;}ListNode* reverseList(ListNode* head){ if(head == nullptr) return head; ListNode* dummy = new ListNode(INT_MIN); doReverse(head, dummy); return dummy->next;}Reverse a linked list from position m to n. Do it in-place and in one-pass.
1) first move (m-1) step to reach the node right before position m, denoted with 'head' 2) use two pointers 'pre' and 'cur' to reverse adjacent nodes, (n-m) times 3) now, 'cur' points to the node right after positions n, and 'pre' is one before 4) update the pointers
ListNode* reverseBetween(ListNode* head, int m, int n) { if(m<1 || m>=n || head==nullptr) return head; ListNode* dummy = new ListNode(INT_MIN); dummy->next = head; head = dummy; //avoid special handle when 'm=1' for(int i=0; i<m-1; ++i) head = head->next; ListNode* pre = head->next, *cur = pre->next; for(int i=0; i<n-m; ++i) { ListNode* next = cur->next; cur->next = pre; pre = cur; cur = next; }//--for head->next->next = cur; head->next = pre; head = dummy->next; delete dummy; return head;}Given a linked list, swap every two adjacent nodes and return its head.
Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed.
ListNode* swapPairs(ListNode* head) { if(head==nullptr || head->next==nullptr) return head; ListNode* dummy = new ListNode(INT_MIN); dummy->next = head; int cnt = 0; ListNode* pre = dummy; ListNode *last=dummy, *cur = pre->next; while(pre->next!=nullptr && pre->next->next!=nullptr) { last = pre->next; cur = last->next; last->next = cur->next; cur->next = pre->next; pre->next = cur; pre = last; }//--while head = dummy->next; delete dummy; return head;}Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
dummy
-----> [1 -> 2 -> 3] ->4 ->5
pre next
1) scan the list, find the 'pre' (one before the seg start) and 'next' (one after seg end)
2) reverse the nodes in between, and return the 'pre' for next seg (i.e, first of current seg) //reverse nodes between 'pre' and 'next' (exclusive), e.g, -1 ->1->2->3 ->4ListNode* revList(ListNode* pre, ListNode* next) { ListNode *last=pre->next, curr=last->next; while(curr != next) { ListNode* nt = curr->next; curr->next = last; last = curr; curr = nt; }//--while ListNode* rtn = pre->next; pre->next->next = curr; pre->next = last; return rtn;}ListNode* reverseKGroup(ListNode* head, int k){ if(head==nullptr || k==1) return head; ListNode* dummy = new ListNode(INT_MIN); dummy->next = head; ListNode *pre=dummy, *cur=pre->next; int cnt = 0; while(cur != nullptr){ ++ cnt; if(cnt % k == 0) { pre = revList(pre, cur->next); cur = pre->next; } else { cur = cur->next; } }//--while head = dummy->next; delete dummy; return head;}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 contain a single digit. Add the two numbers and return it as a linked list.
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode* dummy = new ListNode(INT_MIN); ListNode* p = dummy; int carry = 0; while(l1!=nullptr || l2!=nullptr || carry) { int val1 = (l1==nullptr) ? 0 : l1->val; int val2 = (l2==nullptr) ? 0 : l2->val; int sum = val1 + val2 + carry; carry = sum / 10; p->next = new ListNode(sum%10); p = p->next; if(l1!=nullptr) l1 = l1->next; if(l2!=nullptr) l2 = l2->next; } return dummy.next;}You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
//l1 is larger, l2 is shorterListNode* doAdd(ListNode* l1, ListNode* l2, int offset) { if(l1 == nullptr) return l1; ListNode* result = (offset==0) ? new ListNode(l1->val+l2->val) : new ListNode(l1->val); ListNode* post = (offset==0) ? new ListNode(l1->next, l2->next, 0) : new ListNode(l1->next, l2, offset-1) if(post!=nullptr && post->val > 9) { post->val %= 10; result->val += 1; } result->next = post; return result;}ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { int len1 = getLength(l1); int len2 = getLength(l2); ListNode* dummy = new ListNode(1); if(len1>len2) { dummy->next = helper(l1, l2, len1-len2); } else { dummy->next = helper(l2, l1, len2-len1); } //handle psbl carry if(dummy->next->val > 9) { dummy->next->val %= 10; return dummy; } return dummy->next;}Similar: LC415: Add strings
Given a non-negative integer represented as non-empty a singly linked list of digits, plus one to the integer.
The digits are stored such that the most significant digit is at the head of the list.
ListNode* helper(ListNode* list) { if(list == nullptr) return list; ListNode* post = helper(list->next); if(post != nullptr && post->val>9) { post->val %= 10; list->val += 1; } if(post == nullptr){ list->val += 1; } return list;} ListNode* plusOne(ListNode* head) { if(head == nullptr) return head; ListNode* dummy = new ListNode(0); dummy->next = head; head = dummy; ListNode* p1 = dummy; //find last non-9 node while(head != nullptr) { if(head->val != 9) p1 = head; head = head->next; } p1->val += 1; p1 = p1->next; while(p1 != nullptr) { p1->val = 0; p1 = p1->next; } return dummy->val==1 ? dummy : dummy->next;}Similar: LC66: Plus one
Given a linked list, determine if it has a cycle in it. O(1)
ListNode* slow = head; //slow pointerListNode* fast = head; //fast pointerwhile(fast != nullptr && fast->next!=nullptr) { slow = slow->next; fast = fast->next->next; if(slow == fast) return true;}//--whilereturn false;Given a linked list, return the node where the cycle begins. If there is no cycle, return null. O(1)
L1: distance from 'head' to cycle 'entry' L2: distance from 'entry' to first meeting point C: cycle length When the two pointers meet, L1 travel distance is 'L1+L2' L2 travel distance is 'L1+L2+n*C', n is the times fast pointer travelled in the cycle Faster is 2 times of slower, so we have L1+L2+n*C = 2*(L1+L2) ==> L1=(n-1)C + (C-L2) As '(n-1)C' just reaches the entry, we can see that "ditance from head to entry equals to that of meeting point to entry"
ListNode *fast = head, *slow = head, *entry = head; while(fast!=nullptr && fast->next!=nullptr) { slow = slow->next; fast = fast->next->next; if(fast == slow) { while(entry != slow) { slow = slow->next; entry = entry->next; } return entry; }}//--whilereturn nullptr;Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one. O(1) space, no more than time complexity.
//binary searchint findDuplicate(vector<int>& nums) { int start=1, end=n; while(start <= end) { int mid = start + (end-start)/2; int cnt = 0; for(auto num : nums) { if(num <= mid) ++ cnt; } if(cnt > mid) //there must be duplicate in first half end = mid - 1; else start = mid + 1; //in second half }//--while return start<=n ? start : -1;} //find cycle entryint findDuplicate(vector<int>& nums) { int slow=0, fast=0, find=0; do{ slow = nums[slow]; fast = nums[nums[fast]]; } while (slow != fast); while(find != slow) { slow = nums[slow]; find = nums[find]; } return find;}Similar:
Given a linked list, remove the nth node from the end of list and return its head.
ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode *slow=head, *fast=head; for(int i=0; i<n; ++i) { fast = fast->next; }//--for if(fast == nullptr) { //case: delete head head = head->next; return head; } while(fast != nullptr && fast->next != nullptr) { fast = fast->next; slow = slow->next; }//--while delete(slow->next); slow->next = slow->next->next; return head;} void reorderList(ListNode* head) { if(head == nullptr) return; ListNode *p1 = head, *p2=head; //split list while(p2->next!=nullptr && p2->next->next!=nullptr) { p1 = p1->next; p2 = p2->next->next; } //reverse right half p1->next = reverseList(p1->next); //interleave ListNode* m1 = head; while(m1->next!=nullptr && m1->next->next!=nullptr){ ListNode* next = m1->next; m1->next = p1->next; p1->next = m1->next->next; m1->next->next = next; m1 = next; } }Write a program to find the node at which the intersection of two singly linked lists begins.
Given a singly linked list, determine if it is a palindrome.
Could you do it in O(n) time and O(1) space?
Sort a linked list in O(n log n) time using constant space complexity.
//Merge sortListNode* sort(ListNode* head) { if(head==nullptr || head->next==nullptr) return head; ListNode* fast = head; ListNode* slow = head; while(fast->next!=nullptr && fast->next->next!=nullptr) { fast = fast->next->next; slow = slow->next; }//--while fast = slow; slow = slow->next; fast->next = nullptr; fast = sort(head); slow = sort(slow); return merge(fast, slow);}ListNode* merge(ListNode* l1, ListNode* l2) { ListNode* dummy = new ListNode(INT_MIN); ListNode *p=dummy, *p1=l1, *p2=l2; while(p1!=nullptr && p2!=nullptr) { if(p1->val < p2->val) { p->next = p1; p = p->next; p1 = p1->next; } else { p->next = p2; p = p->next; p2 = p2->next; } }//--while p->next = (p1==nullptr) ? p2 : p1; return dummy->next;}ListNode* sortList(ListNode* head) { }Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
//merge each two//O(1) space, O(nk^2) time: 2n+3n+...+knListNode* mergeKLists(vector<ListNode*>& lists) { if(lists.size() == 0) return nullptr; ListNode* p = lists[0]; for(int i=1; i<lists.size(); ++i) { p = merge2Lists(p, lists[i]); }//--for return p;} //min heap//O(k) space, O(nklogk) time//priority queue size is fixed at 'k', and insertion takes O(logk)//in total, nk values should be inserted into the heap, and thus O(nklogk) timeListNode* mergeKLists(vector<ListNode*>& lists) { if(lists.size() == 0) return nullptr; auto cmp = [](const ListNode* left, const ListNode* right) { return left->val>right->val; }; priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> pq(cmp); for(auto list : lists) { if(list != nullptr) pq.push(list); } ListNode* dummy = new ListNode(INT_MIN); ListNode* tail = dummy; while(!pq.empty()) { tail->next = pq.top(); pq.pop(); tail = tail->next; if(tail->next != nullptr) pq.push(tail->next); }//--while return dummy->next;} //binary search//O(1) space, O(nklogk) timeListNode *mergeKLists(vector<ListNode *> &lists) { if(lists.empty()) return NULL; int end = lists.size()-1; while(end>0) { int begin = 0; while(begin<end) { lists[begin] = merge2Lists(lists[begin], lists[end]); begin++; end--; } } return lists[0];}//see: http://bangbingsyb.blogspot.com/2014/11/leetcode-merge-k-sorted-lists.htmlGiven two arrays, write a function to compute their intersection.
class Solution {public: vector<int> intersect(vector<int>& nums1, vector<int>& nums2) { sort(nums1.begin(), nums1.end()); sort(nums2.begin(), nums2.end()); int n1 = (int)nums1.size(), n2 = (int)nums2.size(); int i1 = 0, i2 = 0; vector<int> res; while(i1 < n1 && i2 < n2){ if(nums1[i1] == nums2[i2]) { res.push_back(nums1[i1]); i1++; i2++; } else if(nums1[i1] > nums2[i2]){ i2++; } else{ i1++; } } return res; }};Sort a linked list using insertion sort.
ListNode* findInsertPos(ListNode* list, int value) { ListNode *p=list, *pos=list; for(; p!=nullptr && p->val<=value; pos=p, p=p->next){} return pos;}ListNode* insertionSort(ListNode* head) { if(head == nullptr) return head; ListNode* dummy = new ListNode(INT_MIN); ListNode *p=head, *pnew=dummy; while(p != nullptr) { ListNode* pos = findInsertPos(pnew, p->val); ListNode* next = p->next; p->next = pos->next; pos->next = p; p = next; }//--while return dummy->next;}Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of the nodes in each of the two partitions.
ListNode* partition(ListNode* head, int x) { if(head == nullptr) return head; ListNode* dummy1 = new ListNode(INT_MIN), *p1=dummy1; ListNode* dummy2 = new ListNode(INT_MIN), *p2=dummy2; while(head != nullptr) { if(head->val < x) { p1->next = head; p1 = p1->next; } else { p2->next = head; p2 = p2->next; } head = head->next; }//--while p1->next = dummy2->next; p2->next = nullptr; delete(dummy2); return dummy1->next; }Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes.
You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity.
ListNode* oddEvenList(ListNode* head) { if(!head) return head; ListNode *odd=head, *evenhead=head->next, *even = evenhead; while(even && even->next) { odd->next = odd->next->next; even->next = even->next->next; odd = odd->next; even = even->next; } odd->next = evenhead; return head; }Given a list, rotate the list to the right by k places, where k is non-negative.
ListNode* rotateRight(ListNode* head, int k) { if(head == nullptr) return head; ListNode* dummy = new ListNode(INT_MIN); dummy->next = head; int len = 1; while(head->next != nullptr) { ++ len; head = head->next; }//--while head->next = dummy->next; //make a circle ListNode* p = dummy->next; for(int i=1; i<len-k%len; ++i) { //k%n, instead of 'k' p = p->next; }//--for dummy->next = p->next; p->next = nullptr; return dummy->next; }Design a Phone Directory which supports the following operations: get(), check() and release().
frequent remove/'get()' and add/'release()' operations
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
Forward lists are sequence containers that allow constant time insert and erase operations anywhere within the sequence. forward_list is implemented as singly-linked list, keeping internally only a link to the next element.
front(): access first element push_front(): insert element at beginning pop_front(): delete first element insert_after: insert elements erase_after: erase elements
List containers are implemented as doubly-linked lists.
front(): access first element back(): access last element push_front(): pop_front(): push_back(): pop_back(): insert(): insert elements erase(): erase elements
template< class T, //type of the stored elements class Container = std::vector<T>, //type of container to store the elements, vector/deque class Compare = std::less<typename Container::value_type> //provide a strict weak ordering> class priority_queue;A priority queue is a container adaptor that provides time lookup of the largest (by default) element, at the expense of insertion and extraction.
top(): access the top element empty(): check whether the underlying container is empty size(): return the #elements push(): insert element and sort the underlying container emplace(): construct element in-place and sort the underlying container pop(): remove the top element swap(): swap the contents
Examples:
priority_queue<int> q;priority_queue<int, std::vector<int>, std::greater<int>> q2;auto cmp = [](int left, int right) { return (left^1) < (right^1); }priority_queue<int, std::vector<int>, decltype(cmp)> q3(cmp);A pointer variable is a variable that stores the address where another object resides. new() returns a pointer to the newly created object.
//NOT use 'new' when automatic variable can be used instead.IntCell m(0); //a local variable, automatically reclaimedIntCell *n = new IntCell(0); //delete n;Dynamic memory managed through built-in pointers (rather than smart pointers) exists until it is explicitly freed. We can avoid memory leak issues by using smart pointers exclusively. The smart pointer will take care of deleting the memory only when there are no remaining smart pointers pointing to that memory.
void use_factory(T arg) { Foo *p = factory(arg); //use p but do not delete it}//p goes out of scope, but the memory to which p points is not freed //factory returns a shared_ptr pointing to a dynamically allocated objectshared_ptr<Foo> factory(T arg) { //process arg as appropriate //shared_ptr will take care of deleting this memory return make_shared<Foo>(arg);}Resetting the value of a pointer after a delete ...
when we delete a pointer, that pointer becomes invalid. Although the pointer is invalid, on may machines the pointer continus to hold the address of the (freed) dynamic memory. After the delete, the pointer becomes what is referred to as a dangling pointer. A dangling pointer is one that refers to memory that once held an object but no longer does so.
int *p(new int(42)); //p points to dynamic memoryauto q = p; //p and q point to the same memorydelete p; //invalidates both p and qp = nullptr; //indicates that p is no longer bound to an objectshared_ptr<int> p1 = new int(1024); //ERROR: must use direct initshared_ptr<int> p2(new int(1024)); //OK: uses direct init