Skip to content

Commit 24a95c9

Browse files
authored
Create problem6
1 parent d240b12 commit 24a95c9

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

daily_coding_problems/problem6

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
Daily Coding Problem #6
2+
Problem
3+
This problem was asked by Google.
4+
5+
An XOR linked list is a more memory efficient doubly linked list. Instead of each node holding next and prev fields, it holds a field named both, which is an XOR of the next node and the previous node. Implement an XOR linked list; it has an add(element) which adds the element to the end, and a get(index) which returns the node at index.
6+
7+
If using a language that has no pointers (such as Python), you can assume you have access to get_pointer and dereference_pointer functions that converts between nodes and memory addresses.
8+
9+
Solution
10+
For the head, both will just be the address of next, and if it's the tail, it should just be the address of prev. And intermediate nodes should have an XOR of next and prev.
11+
12+
Here's an example XOR linked list which meets the above conditions:
13+
14+
A <-> B <-> C <-> D
15+
16+
B A ⊕ C B ⊕ D C
17+
Let's work through get first, assuming that the above conditions are maintained. Then, given a node, to go to the next node, we have to XOR the current node's both with the previous node's address. And to handle getting the next node from the head, we would initialize the previous node's address as 0.
18+
19+
So in the above example, A's both is B which when XOR'd with 0 would become B. Then B's both is A ⊕ C, which when XOR'd with A becomes C, etc.
20+
21+
To implement add, we would need to update current tail's both to be XOR'd by its current both the new node's memory address. Then the new node's both would just point to the memory address of the current tail. Finally, we'd update the current tail to be equal to the new node.
22+
23+
import ctypes
24+
25+
26+
# This is hacky. It's a data structure for C, not python.
27+
class Node(object):
28+
def __init__(self, val):
29+
self.val = val
30+
self.both = 0
31+
32+
33+
class XorLinkedList(object):
34+
def __init__(self):
35+
self.head = self.tail = None
36+
self.__nodes = [] # This is to prevent garbage collection
37+
38+
def add(self, node):
39+
if self.head is None:
40+
self.head = self.tail = node
41+
else:
42+
self.tail.both = id(node) ^ self.tail.both
43+
node.both = id(self.tail)
44+
self.tail = node
45+
46+
# Without this line, Python thinks there is no way to reach nodes between
47+
# head and tail.
48+
self.__nodes.append(node)
49+
50+
51+
def get(self, index):
52+
prev_id = 0
53+
node = self.head
54+
for i in range(index):
55+
next_id = prev_id ^ node.both
56+
57+
if next_id:
58+
prev_id = id(node)
59+
node = _get_obj(next_id)
60+
else:
61+
raise IndexError('Linked list index out of range')
62+
return node
63+
64+
65+
def _get_obj(id):
66+
return ctypes.cast(id, ctypes.py_object).value
67+
add runs in O(1) time and get runs in O(N) time.

0 commit comments

Comments
 (0)