Post

Linked List

Sort

Sort List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public ListNode sortList(ListNode head) {
    ListNode dummy = new ListNode();
    dummy.next = head;
    int n = 0;
    while (head != null) {
        head = head.next;
        n++;
    }

    for (int step = 1; step < n; step <<= 1) {
        ListNode prev = dummy, curr = dummy.next;
        while (curr != null) {
            ListNode left = curr, right = split(left, step);
            curr = split(right, step);
            prev = merge(left, right, prev);
        }
    }

    return dummy.next;
}

private ListNode split(ListNode head, int step) {
    if (head == null) {
        return null;
    }

    for (int i = 1; head.next != null && i < step; i++) {
        head = head.next;
    }

    ListNode right = head.next;
    head.next = null;
    return right;
}

private ListNode merge(ListNode left, ListNode right, ListNode prev) {
    ListNode curr = prev;
    while (left != null && right != null) {
        if (left.val < right.val) {
            curr.next = left;
            left = left.next;
        } else {
            curr.next = right;
            right = right.next;
        }
        curr = curr.next;
    }

    if (left != null) {
        curr.next = left;
    } else if (right != null) {
        curr.next = right;
    }

    while (curr.next != null) {
        curr = curr.next;
    }
    return curr;
}

Cycle Detection

Floyd’s Tortoise and Hare

Floyd's Tortoise and Hare

Linked List Cycle II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public ListNode detectCycle(ListNode head) {
    ListNode tortoise = head, hare = head;

    while (hare != null && hare.next != null) {
        tortoise = tortoise.next;
        hare = hare.next.next;

        // finds the first meeing point
        if (tortoise == hare) {
            // resets tortoise to head
            tortoise = head;
            while (tortoise != hare) {
                tortoise = tortoise.next;
                hare = hare.next;
            }
            return hare;
        }
    }

    return null;
}

This algorithm can be used to detect duplicate elements in an array, too.

Find the Duplicate Number

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int findDuplicate(vector<int>& nums) {
    // Finds the first meeting point
    int tortoise = nums[0], hare = nums[0];
    do {
        tortoise = nums[tortoise];
        hare = nums[nums[hare]];
    } while (tortoise != hare);

    // Resets `tortoise` to head
    tortoise = nums[0];
    while (tortoise != hare) {
        tortoise = nums[tortoise];
        hare = nums[hare];
    }
    return hare;
}

A hidden condition is nums[0] != 0, otherwise the tortoise and hare will stay at 0 forever.

Happy Number

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public boolean isHappy(int n) {
    // finds meeting point
    int tortoise = n, hare = getNext(n);
    while (hare != 1 && tortoise != hare) {
        tortoise = getNext(tortoise);
        hare = getNext(getNext(hare));
    }
    return hare == 1;
}

private int getNext(int n) {
    int sum = 0;
    while (n > 0) {
        sum += (n % 10) * (n % 10);
        n /= 10;
    }
    return sum;
}

Reverse

Palindrome Linked List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
bool isPalindrome(ListNode* head) {
    ListNode *fast = head, *slow = head;
    while (fast && fast->next) {
        fast = fast->next->next;
        slow = slow->next;
    }

    // If there are n nodes in the list and the nodes are 0 indexed,
    // then `slow` is at the (n / 2)-th node.
    // Reverse the second half list: [n/2, n)
    ListNode *prev = slow, *tmp = nullptr;
    slow = slow->next;
    prev->next = nullptr;

    while (slow) {
        tmp = slow->next;
        slow->next = prev;
        prev = slow;
        slow = tmp;
    }

    // First node
    fast = head;
    // Last node
    slow = prev;
    while (slow) {
        if (fast->val != slow->val) {
            return false;
        }
        fast = fast->next;
        slow = slow->next;
    }
    return true;
}

Add Two Numbers II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    return addTwoNumbers(l1, l2, size(l1), size(l2));
}

private ListNode addTwoNumbers(ListNode l1, ListNode l2, int s1, int s2) {
    if (s1 < s2) {
        return addTwoNumbers(l2, l1, s2, s1);
    }

    // s1 >= s2
    // adds the two lists with tails aligned
    // carry is not considered yet
    ListNode head = null, curr = null;
    while (s1 > 0) {
        // creates the result list in reverse order
        curr = new ListNode(l1.val + (s1 > s2 ? 0 : l2.val));
        curr.next = head;
        head = curr;

        if (s1-- == s2) {
            s2--;
            l2 = l2.next;
        }
        l1 = l1.next;
    }

    // normalization
    head = null;
    int carry = 0;
    while (curr != null) {
        curr.val += carry;
        carry = curr.val / 10;
        curr.val %= 10;

        // reverses the result list on the fly
        ListNode tmp = curr.next;
        curr.next = head;
        head = curr;
        curr = tmp;
    }

    // adds a new head if carry exists
    if (carry > 0) {
        curr = new ListNode(1);
        curr.next = head;
        head = curr;
    }
    return head;
}

private int size(ListNode l) {
    int s = 0;
    while (l != null) {
        l = l.next;
        s++;
    }
    return s;
}

Clone

Copy List with Random Pointer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public Node copyRandomList(Node head) {
    Node curr = head, next = null;

    // links each copy node to its original node
    while (curr != null) {
        next = curr.next;
        Node copy = new Node(curr.val);
        curr.next = copy;
        copy.next = next;
        curr = next;
    }

    // assigns random pointers for the copy nodes
    curr = head;
    while (curr != null) {
        if (curr.random != null) {
            curr.next.random = curr.random.next;
        }
        curr = curr.next.next;
    }

    curr = head;
    Node dummyCopyHead = new Node(0);
    Node copyCurr = dummyCopyHead, copyNext = null;

    while (curr != null) {
        // extracts the copy list
        copyNext = curr.next;
        copyCurr.next = copyNext;
        copyCurr = copyNext;

        // restores the original list
        next = curr.next.next;
        curr.next = next;
        curr = next;
    }

    return dummyCopyHead.next;
}

Tree

Populating Next Right Pointers in Each Node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public Node connect(Node root) {
    if (root == null) {
        return root;
    }

    Node leftmost = root;
    while (leftmost.left != null) {
        // starts from leftmost node in each level
        Node head = leftmost;

        while (head != null) {
            // inner connection
            head.left.next = head.right;

            // inter connection
            if (head.next != null) {
                head.right.next = head.next.left;
            }

            head = head.next;
        }

        // moves to the next level
        leftmost = leftmost.left;
    }
    return root;
}

Generalizing it with an arbitrary binary tree:

Populating Next Right Pointers in Each Node II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// the previous node on the next level
// we're about to connect a new node as its next
private Node prev = null;
// leftmost node of the current level
private Node leftmost = null;

public Node connect(Node root) {
    if (root == null) {
        return root;
    }

    leftmost = root;
    Node curr = leftmost;

    while (leftmost != null) {
        curr = leftmost;
        prev = leftmost = null;
        while (curr != null) {
            helper(curr.left);
            helper(curr.right);
            curr = curr.next;
        }
    }

    return root;
}

private void helper(Node node) {
    if (node != null) {
        if (prev == null) {
            // current node is the first node of the next level
            leftmost = node;
        } else {
            // connects current node to the previous node
            prev.next = node;
        }    
        prev = node; 
    }
}

Double Linked List

Circular Double Linked List

Design Most Recently Used Queue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// sqrt decomposition
// seats are split to buckets
// nodes are items
// each bucket contains a circular double linked list of nodes
private Node[] buckets;
// count of nodes in each bucket
private int m;

public MRUQueue(int n) {
    this.m = (int)Math.sqrt(n);
    // Math.ceil(n / m)
    this.buckets = new Node[(n + m - 1) / m];

    for (int i = 0; i < buckets.length; i++) {
        buckets[i] = new Node(0);
    }

    // bucket index for seat i: (i - 1) / m
    for (int i = 1; i <= n; i++) {
        buckets[(i - 1) / m].prepend(new Node(i));
    }
}

public int fetch(int k) {
    // bucket index for seat k: (k - 1) / m
    Node node = buckets[(k - 1) / m].next;
    // target seat index in the bucket: (k - 1) % m
    for (int i = 0; i < (k - 1) % m; i++) {
        node = node.next;
    }
    node.remove();

    // for each bucket after the current bucket,
    // moves one item to its previous bucket
    for (int i = 1 + (k - 1) / m; i < buckets.length; i++) {
        buckets[i - 1].prepend(buckets[i].next.remove());
    }
    buckets[buckets.length - 1].prepend(node);
    return node.val;
}

class Node {
    Node prev = this, next = this;
    int val;

    Node(int val) {
        this.val = val;
    }

    // prepends `node` to this node
    public void prepend(Node node) {
        this.prev.next = node;
        node.prev = this.prev;
        this.prev = node;
        node.next = this;
    }

    public Node remove() {
        prev.next = next;
        next.prev = prev;
        return next = prev = this;
    }
}
This post is licensed under CC BY 4.0 by the author.