When to use:
Tips:
a. If a node->next is effected, then we need to correct this pointer.
b. If the node to be deleted is dynamically allocated memory, we need to reallocate these memory.
Code:
ListNode* dummy = new ListNode(0);
dummy->next = head;
Example:
When to use:
Code:
ListNode* chaser= head, * runner = head;
while(chaser->next && runner->next->next){
chaser = chaser->next;
runner = runner->next->next;
}
Example:
Doubly Linked List in C++ is std::list< T>
Frequent iterator: begin(), end(), rbegin(), rend()
Frequent functions: empty(), size(), push_back(T value), pop_back(T value), erase(iterator pos), insert(iterator pos, T value).
When iterating the linked list, each time only process one/pair nodes. The core node is the current node, or else it’s easily cause duplicate-process problem.
372. Delete Node in a Linked List
void deleteNode(ListNode * node) {
// write your code here
if (node) {
node->val = node->next->val;
node->next = node->next->next;
}
}
class Solution {
public:
/**
* @param head: a ListNode
* @param k: An integer
* @return: a ListNode
*/
ListNode * reverseKGroup(ListNode * head, int k) {
// write your code here
// There are two main parts: repeated reverse Linked list, and the size would be k
ListNode* dummy = new ListNode(0);
dummy->next = head;
head = dummy;
while(head->next){
head = reverseNextK(head, k);
}
return dummy->next;
}
ListNode* reverseNextK(ListNode* head, int k){
// check if there is k nodes to be reversed
ListNode* nk = head;
for(int i = 0; i < k; i++){
if(!nk->next){
return nk;
}
nk = nk->next;
}
//Before: head->n1->n2->..->nk->..
//After : head->nk->nk-1->..->n1->..
ListNode* n1 = head->next;
ListNode* curr = n1, *next = curr->next;
for(int i = 0; i< k-1; i++){
if(!next){
n1->next = nullptr;
break;
}
ListNode* tmp = next->next;
next->next = curr;
curr = next;
next = tmp;
}
head->next = curr;
n1->next = next;
return n1;
}
};
ListNode * partition(ListNode * head, int x) {
// write your code here
ListNode* smaller = new ListNode(0);
ListNode* larger = new ListNode(0);
ListNode* n1 = smaller, *n2 = larger;
while(head){
ListNode* nxt = head ->next;
head ->next = nullptr;
if(head ->val < x){
n1 ->next = head;
n1 = n1 ->next;
} else {
n2 ->next = head;
n2 = n2 ->next;
}
head = nxt;
}
n1 ->next = larger ->next;
return smaller ->next;
}
If we want to swap two nodes(except deleting), their previous nodes and next nodes will be effected. However, under any circumstance, we can always do this without error:
a. Swap the value of both prvious_node->next
b. Swap the value of both node->next
511. Swap Two Nodes in Linked List
As it’snot allowed to swap the value directly, we need to record the prev/post pointer of two value nodes.
One thing need to be mentioned is the corner cases:
ListNode * swapNodes(ListNode * head, int v1, int v2) {
// write your code here
if(!head)
return head;
ListNode* dummy = new ListNode(0);
dummy ->next = head;
ListNode *prev_v1 = dummy, *v1_ = dummy ->next, *post_v1;
while(v1_ && v1_ ->val != v1) {
post_v1 = v1_ ->next;
prev_v1 = v1_;
v1_ = post_v1;
}
post_v1 = v1_ ? v1_ ->next : nullptr;
ListNode *prev_v2 = dummy, *v2_ = dummy ->next, *post_v2;
while(v2_ && v2_ ->val != v2) {
post_v2 = v2_ ->next;
prev_v2 = v2_;
v2_ = post_v2;
}
post_v2 = v2_ ? v2_ ->next : nullptr;
if(! v1_ || !v2_)
return dummy ->next;;
if (post_v1 == v2_) {
prev_v1 ->next = v2_;
v2_ ->next = v1_;
v1_ ->next = post_v2;
return dummy ->next;
}
if (prev_v1 == v2_) {
prev_v2 ->next = v1_;
v1_ ->next = v2_;
v2_ ->next = post_v1;
return dummy ->next;
}
prev_v1 ->next = v2_;
prev_v2 ->next = v1_;
v1_ ->next = post_v2;
v2_ ->next = post_v1;
return dummy ->next;
}
36. Reverse Linked List II
For the special position, such as the previous node of M and post node of N, we need extra pointer to keep its position, in case of mistakes.
ListNode * reverseBetween(ListNode * head, int m, int n) {
// write your code here
if(m >= n || !head)
return head;
ListNode *dummy = new ListNode(0);
dummy ->next = head;
head = dummy;
for(int i = 0; i < m -1; i++){
if( !head)
return nullptr;
head = head ->next;
}
ListNode *premNode = head;
ListNode *mNode = head ->next;
ListNode *nNode = mNode, *postnNode = mNode ->next;
for(int i = m; i < n; i++) {
if(! postnNode )
return nullptr;
ListNode *tmp = postnNode ->next;
postnNode ->next = nNode;
nNode = postnNode;
postnNode = tmp;
}
mNode ->next = postnNode;
premNode ->next = nNode;
return dummy ->next;
}
When we handle two lists at the same time ,we could user while(l1 && l2), and then handle the non-nullptr list.
ListNode * mergeTwoLists(ListNode * l1, ListNode * l2) {
// write your code here
ListNode* dummy = new ListNode(0);
ListNode *ptr = dummy;
while(l1 && l2){
if(l1->val <= l2 ->val){
ptr ->next = l1;
l1 = l1 ->next;
} else {
ptr ->next = l2;
l2 = l2 ->next;
}
ptr = ptr ->next;
}
while(l1)
{
ptr ->next = l1;
l1 = l1 ->next;
ptr = ptr ->next;
}
while(l2)
{
ptr ->next = l2;
l2 = l2 ->next;
ptr = ptr ->next;
}
return dummy ->next;
}
void reorderList(ListNode * head) {
// write your code here
if(! head)
return;
ListNode *runner = head, *chaser = head;
while(runner ->next && runner ->next ->next) {
runner = runner ->next ->next;
chaser = chaser ->next;
}
if(runner == chaser)
return;
runner = chaser ->next;
chaser ->next = nullptr;
// reverse the latter part of the ListNode
ListNode * prev, * ptr, * nxt;
prev = runner;
ptr = prev ->next;
prev ->next = nullptr;
while(ptr) {
nxt = ptr ->next;
ptr ->next = prev;
prev = ptr;
ptr = nxt;
}
ptr = prev;
ListNode* dummy = new ListNode(0);
ListNode *node = dummy;
bool isAlter = false;
while(head && ptr) {
if(!isAlter) {
node ->next = head;
head = head ->next;
node = node ->next;
isAlter = !isAlter;
} else {
isAlter = !isAlter;
node ->next = ptr;
ptr = ptr ->next;
node = node ->next;
}
}
if(head)
node ->next = head;
if(ptr)
node ->next = ptr;
head = dummy ->next;
}
ListNode * rotateRight(ListNode * head, int k) {
// write your code here
if( ! head)
return head;
int len = 0;
ListNode *ptr = head;
while(ptr ) {
len ++;
ptr = ptr ->next;
}
k = k % len;
if(k == 0)
return head;
ListNode *fast = head;
for(int i = 0; i < k; i ++) {
fast = fast ->next;
}
ListNode *slow = head;
while(fast ->next) {
slow = slow ->next;
fast = fast ->next;
}
fast ->next = head;
head = slow ->next;
slow ->next = nullptr;
return head;
}
If the process of the current node is based on the next node, which is reversely traverse problem, we could use recursion, or stack.
void traverse(ListNode* head)
{
if(head == nullptr)
return;
traverse(head->next);
visit(head);
}
106. Convert Sorted List to Binary Search Tree
class Solution {
public:
/**
* @param head: The first node of linked list.
* @return: a tree node
*/
TreeNode *sortedListToBST(ListNode *head) {
if (head == NULL) {
return NULL;
}
int size = getListSize(head);
return convertHelper(head, size);
}
int getListSize(ListNode *head) {
int size = 0;
while (head != NULL) {
head = head->next;
size++;
}
return size;
}
TreeNode *convertHelper(ListNode *&head, int size) {
if (size == 0) {
return NULL;
}
TreeNode *root = new TreeNode(0);
root->left = convertHelper(head, size / 2);
root->val = head->val; head = head->next;
root->right = convertHelper(head, size - size / 2 - 1);
return root;
}
};
To deep copy a list, we usually use hash map to relate the new node and old node.
105. Copy List with Random Pointer
RandomListNode *copyRandomList(RandomListNode *head) {
// write your code here
if(! head)
return head;
unordered_map<RandomListNode*, RandomListNode*> hash;
RandomListNode *dummy = new RandomListNode(0);
RandomListNode *ptr = dummy, *curt = head;
while(curt) {
RandomListNode *new_node = new RandomListNode(curt ->label);
hash[curt] = new_node;
ptr ->next = new_node;
curt = curt ->next;
ptr = ptr ->next;
}
curt = head;
while(curt) {
hash[curt] ->random = curt->random? hash[curt ->random] : nullptr;
curt = curt ->next;
}
return dummy ->next;
}
Based on the runner-chaser technique, let the runner use twice speed of the chaser. If there exists circle, the runner and chaser will meet at some position.
bool hasCycle(ListNode * head) {
// write your code here
if (!head || !head ->next)
return false;
ListNode *slow = head, *fast = head ->next;
while(slow != fast) {
if (!fast || ! (fast ->next) )
return false;
slow = slow ->next;
fast = fast ->next ->next;
}
return true;
}
Based on previous problem, let the runner use twice speed of the chaser. When they are first time met, move the chaser from the met position to the head, the second time they met is the beginning of the circle.
ListNode * detectCycle(ListNode * head) {
// write your code here
if(!head || ! head ->next)
return nullptr;
ListNode *slow = head, *fast = head ->next;
while(slow != fast) {
if( !fast || ! fast ->next)
return nullptr;
slow = slow ->next;
fast = fast ->next ->next;
}
while(head != slow ->next) {
slow = slow ->next;
head = head ->next;
}
return head;
}
To determine whether exists the intersection of two linked list, we need to check whether two lists have circles.
1. If one have circle while the other don’t, they is no intersection.
2. If neither has circle, check if their end nodes are the same.
3. If both has circles, find the Z point(intersection of the circle) of a list, and check if this Z point is in the other list.
How to find the first intersection of two lists?
Get the length of two lists and the gap of two lists, and then, use chaser-runner. Let runner is gap-size faster than the chaser. The first place they met is the first intersection they have.