Balanced Search Trees
Red–black BST with no extra memory. Describe how to save the memory for storing the color information when implementing a red–black BST.
Hint: modify the structure of the BST to encode the color information.
BST需要满足 左结点L < 根结点P < 右结点R,那么这样设定:如果 L > P,那么说明L为红结点;如果 R < P,那么说明R为红结点。因此在左偏红黑树中,将一个结点标记为红色的方法是:将结点red的值变为 r e d . v a l u e = 2 ∗ p a r e n t − r e d . v a l u e red.value=2*parent-red.value red.value=2∗parent−red.value。
public class LLRB {
private static final int LEFT = 1;
private static final int RIGHT = 2;
private Node root;
public boolean search(int target) {
Node x = root;
int preValue = x.val;
int flag = 0;
while (x != null) {
int trueValue = x.val;
if (flag == LEFT && trueValue > preValue) {
trueValue = 2 * preValue - trueValue;
}
if (target < trueValue) {
x = x.left;
flag = LEFT;
preValue = trueValue;
} else if (target > trueValue) {
x = x.right;
} else {
return true;
}
}
return false;
}
public void insert(int val) {
insert(root, val, 0, 0);
root.val = -1 * root.val;
}
private Node insert(Node x, int val, int preValue, int flag) {
if (x == null) {
return new Node(2 * preValue - val);
}
int trueValue = x.val;
if (flag == LEFT && trueValue > preValue) {
trueValue = 2 * preValue - trueValue;
}
if (val < trueValue) {
x.left = insert(x.left, val, trueValue, LEFT);
} else if (val > trueValue) {
x.right = insert(x.right, val, trueValue, RIGHT);
}
if ((x.right != null && x.right.val > trueValue) && (x.left == null || x.left.val < trueValue)) {
x = rotateLeft(x, trueValue, trueValue != x.val);
}
if (x.left != null && x.left.left != null && x.left.val > trueValue
&& x.left.left.val > (2 * (2 * trueValue - x.left.val) - x.left.left.val)) {
x = rotateRight(x, trueValue, trueValue != x.val);
}
if ((x.left != null && x.left.val > trueValue) && (x.right != null && x.right.val < trueValue)) {
flipColors(x, trueValue);
}
return x;
}
private Node rotateLeft(Node x, int preValue, boolean isRed) {
Node y = x.right;
if (isRed) {
x.val = 2 * preValue - x.val;
}
y.val = 2 * x.val - y.val;
x.right = y.left;
y.left = x;
x.val = 2 * y.val - x.val;
if (isRed) {
y.val = 2 * preValue - y.val;
}
return y;
}
private Node rotateRight(Node x, int preValue, boolean isRed) {
Node y = x.left;
if (isRed) {
x.val = 2 * preValue - x.val;
}
y.val = 2 * x.val - y.val;
x.left = y.right;
y.right = x;
x.val = 2 * y.val - x.val;
if (isRed) {
y.val = 2 * preValue - y.val;
}
return y;
}
private void flipColors(Node x, int preValue) {
x.left.val = 2 * x.val - x.left.val;
x.right.val = 2 * x.val - x.right.val;
x.val = 2 * preValue - x.val;
}
private class Node {
Node left, right;
int val;
Node(int val) {
this.val = val;
}
}
}
Document search. Design an algorithm that takes a sequence of n document words and a sequence of m query words and find the shortest interval in which the m query words appear in the document in the order given. The length of an interval is the number of words in that interval.
Hint: for each word, maintain a sorted list of the indices in the document in which that word appears. Scan through the sorted lists of the query words in a judicious manner.
题目大意:给定一组n个被查找单词,和一组m个待查找单词,要求在n个被查找单词中找到一个最小区间,使得这个区间包含所有m个待查找单词,且这m个单词出现的顺序和给定的顺序一致。
解法:给每一个不同的单词开一个列表,记录该单词在n个被查找单词中出现的下标位置(有序);得到m个待查找单词对应的位置列表,从这m个列表中各挑出一个数字组成序列,要求该序列首尾之差最小,且要保证序列为递增序列。
import java.util.*;
public class Document {
private String[] document;
private String[] query;
public void search() {
// 记录满足条件的最短区间的两个端点
// 将first设为-1有助于判断最终能否找到有效的区间
int first = -1, last = document.length - 1;
// 根据每个不同的单词生成对应的递增下标序列
Map<String, Queue<Integer>> map = new HashMap<>();
for (int i = 0; i < document.length; i++) {
if (!map.containsKey(document[i])) {
Queue<Integer> q = new LinkedList<>();
q.add(i);
map.put(document[i], q);
} else {
map.get(document[i]).add(i);
}
}
// 摘出m个待查找单词对应的下标序列
Queue<Integer>[] q = new Queue[query.length];
for (int i = 0; i < query.length; i++) {
q[i] = map.get(query[i]);
}
// 搜寻满足条件的区间
OUTER:
for (int i : q[0]) {
int left = i, right = i; // 记录当前区间的两个端点
for (int j = 1; j < q.length; j++) {
// 每次都选取各序列中满足条件的最小的位置,并出队小于这个位置的所有下标
while (!q[j].isEmpty() && q[j].peek() <= right) {
q[j].poll();
}
if (q[j].isEmpty()) {
break OUTER; // 当某一单词对应下标全出队后,可直接跳出外层循环
} else {
right = q[j].peek(); // 更新当前区间的右端点
}
}
// 更新最短区间的左右端点
if (right - left < last - first) {
first = left;
last = right;
}
}
if (first != -1) {
System.out.println(last - first);
} else {
System.out.println("Not Found");
}
}
}
Generalized queue. Design a generalized queue data type that supports all of the following operations in logarithmic time (or better) in the worst case.
- Create an empty data structure.
- Append an item to the end of the queue.
- Remove an item from the front of the queue.
- Return the i t h i^{th} ith item in the queue.
- Remove the i t h i^{th} ith item from the queue.
Hint: create a red–black BST where the keys are integers and the values are the items such that the i t h i^{th} ith largest integer key in the red–black BST corresponds to the i t h i^{th} ith item in the queue.
用红黑树构建的符号表来储存队列元素,key值记录入队序号,value值储存对应item。出队则找最小的序号,入队则加入一个新序号;找到第i大的元素,就是在树中找到序号第i大的结点,这与之前BST实现的符号表中的select()实现方法是一样的。