二分探索木の合計で値になる 2 つのノードを見つけることは、並べ替えられた配列で合計して値になる 2 つの要素を見つけるのと同様の方法で行うことができます。
配列が小さいものから大きいものに並べ替えられている場合、2 つのポインターを保持します。1 つは最初から、もう 1 つは最後から始まります。ポインターが指す 2 つの要素の合計がターゲットよりも大きい場合は、右のポインターを左に 1 つ移動し、合計がターゲットよりも小さい場合は、左のポインターを右に 1 つ移動します。最終的に、2 つのポインターは、合計がターゲット値になる 2 つの要素を指すか、中間で一致します。
boolean searchNumArray(int[] arr, int num) {
int left = 0;
int right = arr.length - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == num) {
return true;
} else if (sum > num) {
right--;
} else {
left++;
}
}
return false;
}
二分探索木を順番に走査すると、ソートされた配列になります。したがって、同じ考え方を二分探索木に適用できます。
次のコードは、双方向から順番にトラバーサルを繰り返します。トラバーサルにはスタックが使用されているため、時間計算量は O(n) で、空間計算量は O(h) です。ここで、h はバイナリ ツリーの高さです。
class BinTreeIterator implements Iterator<BinTreeNode> {
Stack<BinTreeNode> stack;
boolean leftToRight;
public boolean hasNext() {
return !stack.empty();
}
public BinTreeNode next() {
return stack.peek();
}
public void remove() {
BinTreeNode node = stack.pop();
if (leftToRight) {
node = node.rightChild;
while (node.rightChild != null) {
stack.push(node);
node = node.rightChild;
}
} else {
node = node.leftChild;
while (node.leftChild != null) {
stack.push(node);
node = node.leftChild;
}
}
}
public BinTreeIterator(BinTreeNode node, boolean leftToRight) {
stack = new Stack<BinTreeNode>();
this.leftChildToRight = leftToRight;
if (leftToRight) {
while (node != null) {
stack.push(node);
node = node.leftChild;
}
} else {
while (node != null) {
stack.push(node);
node = node.rightChild;
}
}
}
}
public static boolean searchNumBinTree(BinTreeNode node, int num) {
if (node == null)
return false;
BinTreeIterator leftIter = new BinTreeIterator(node, true);
BinTreeIterator rightIter = new BinTreeIterator(node, false);
while (leftIter.hasNext() && rightIter.hasNext()) {
BinTreeNode left = leftIter.next();
BinTreeNode right = rightIter.next();
int sum = left.item + right.item;
if (sum == num) {
return true;
} else if (sum > num) {
rightIter.remove();
if (!rightIter.hasNext() || rightIter.next() == left) {
return false;
}
} else {
leftIter.remove();
if (!leftIter.hasNext() || leftIter.next() == right) {
return false;
}
}
}
return false;
}