ツリーが対称かどうかをテストするための基本的なアルゴリズムは何ですか。それは二分木なので、ソートの再帰的な定義になると思います
正式な質問は次のとおりです。
バイナリツリーは、左右のサブツリーが同一のミラーイメージである場合、つまりバイナリツリーが対称である場合、それ自体のミラーイメージです。これは、いくつかの例を使用して説明するのが最適です。
1
/ \
2 2
TRUE
1
/ \
2 2
\
3
FALSE
1
/ \
2 2
/ \ / \
4 3 3 4
TRUE
1
/ \
2 2
/ \ / \
3 4 3 4
FALSE
1
/ \
2 2
/ \
3 3
TRUE
選択したプログラミング言語で、BTreeクラス/ C構造体と関連メソッドを定義して、ツリーが鏡像かどうかを確認します。静的に型付けされた言語の場合、ノード値はすべて整数であると想定できます。
Class/structure definition
BTree {
BTree left;
BTree right;
int value;
}
ツリーのルートが呼び出し元によって追跡され、関数isMirror()が呼び出されると仮定します。
また、クラスを定義する場合、データ要素にパブリックにアクセスできない場合は、引数のないコンストラクターとゲッター/セッターメソッドを必ず提供してください。
次の関数でmirrorEquals(root.left、root.right)を呼び出すのはどうですか:-
boolean mirrorEquals(BTree left, BTree right) {
if (left == null || right == null) return left == null && right == null;
return left.value == right.value
&& mirrorEquals(left.left, right.right)
&& mirrorEquals(left.right, right.left);
}
基本的に、左のサブツリーと反転した右のサブツリーを比較して、ルート全体に仮想の反転線を描きます。
解決策1-再帰的に:
bool isMirror(BinaryTreeNode *a, BinaryTreeNode *b)
{
return (a && b) ?
(a->m_nValue==b->m_nValue
&& isMirror(a->m_pLeft,b->m_pRight)
&& isMirror(a->m_pRight,b->m_pLeft)) :
(a == b);
}
bool isMirrorItselfRecursively(BinaryTreeNode *root)
{
if (!root)
return true;
return isMirror(root->m_pLeft, root->m_pRight);
}
解決策2-繰り返し:
bool isMirrorItselfIteratively(BinaryTreeNode *root)
{
/// use single queue
if(!root) return true;
queue<BinaryTreeNode *> q;
q.Push(root->m_pLeft);
q.Push(root->m_pRight);
BinaryTreeNode *l, *r;
while(!q.empty()) {
l = q.front();
q.pop();
r = q.front();
q.pop();
if(l==NULL && r==NULL) continue;
if(l==NULL || r==NULL || l->m_nValue!=r->m_nValue) return false;
q.Push(l->m_pLeft);
q.Push(r->m_pRight);
q.Push(l->m_pRight);
q.Push(r->m_pLeft);
}
return true;
}
Javaの再帰および反復ソリューション上記のアプローチを使用
再帰
public Boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return isSymmetricInternal(root.left, root.right);
}
private Boolean isSymmetricInternal(TreeNode leftNode,
TreeNode rightNode) {
boolean result = false;
// If both null then true
if (leftNode == null && rightNode == null) {
result = true;
}
if (leftNode != null && rightNode != null) {
result = (leftNode.data == rightNode.data)
&& isSymmetricInternal(leftNode.left, rightNode.right)
&& isSymmetricInternal(leftNode.right, rightNode.left);
}
return result;
}
反復LinkedListをQueueとして使用
private Boolean isSymmetricRecursive(TreeNode root) {
boolean result = false;
if (root == null) {
return= true;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root.left);
queue.offer(root.right);
while (!queue.isEmpty()) {
TreeNode left = queue.poll();
TreeNode right = queue.poll();
if (left == null && right == null) {
result = true;
}
else if (left == null ||
right == null ||
left.data != right.data) {
// It is required to set result = false here
result = false;
break;
}
else if (left != null && right != null) {
queue.offer(left.left);
queue.offer(right.right);
queue.offer(left.right);
queue.offer(right.left);
}
}
return result;
}
テストケース
@Test
public void testTree() {
TreeNode root0 = new TreeNode(1);
assertTrue(isSymmetric(root0));
assertTrue(isSymmetricRecursive(root0));
TreeNode root1 = new TreeNode(1, new TreeNode(2), new TreeNode(2));
assertTrue(isSymmetric(root1));
assertTrue(isSymmetricRecursive(root1));
TreeNode root2 = new TreeNode(1,
new TreeNode(2, null, new TreeNode(3)), new TreeNode(2));
assertFalse(isSymmetric(root2));
assertFalse(isSymmetricRecursive(root2));
TreeNode root3 = new TreeNode(1, new TreeNode(2, new TreeNode(4),
new TreeNode(3)), new TreeNode(2, new TreeNode(3),
new TreeNode(4)));
assertTrue(isTreeSymmetric(root3));
assertTrue(isSymmetricRecursive(root3));
TreeNode root4 = new TreeNode(1, new TreeNode(2, new TreeNode(3),
new TreeNode(4)), new TreeNode(2, new TreeNode(3),
new TreeNode(4)));
assertFalse(isSymmetric(root4));
assertFalse(isSymmetricRecursive(root4));
}
ツリーノードクラス
public class TreeNode {
int data;
public TreeNode left;
public TreeNode right;
public TreeNode(int data){
this(data, null, null);
}
public TreeNode(int data, TreeNode left, TreeNode right)
{
this.data = data;
this.left = left;
this.right = right;
}
}
@gvijayからの再帰的なソリューションは非常に明確であり、ここに反復的なソリューションがあります。
ツリーの各行を上から下に検査し、値が回文であるかどうかを確認します。それらがすべてそうであれば、はい、それは鏡です。各行を訪問し、スパースツリーのnull値を含めるためのアルゴリズムを実装する必要があります。擬似コードで:
boolean isMirror(BTree tree) {
foreach (List<Integer> row : tree.rows() {
if (row != row.reverse()) return false;
}
return true;
}
秘Theは、スパースツリーがプレースホルダーとしてnull値を持つ必要があることを考慮して、ツリーの行を反復するアルゴリズムを設計することです。このJava実装は問題ないようです:
public static boolean isMirror(BTree root) {
List<BTree> thisRow, nextRow;
thisRow = Arrays.asList(root);
while (true) {
// Return false if this row is not a palindrome.
for (int i=0; i<thisRow.size()/2; i++) {
BTree x = thisRow.get(i);
BTree y = thisRow.get(thisRow.size()-i-1);
if ((x!=null) && (y!=null)
&& (x.value != y.value))
return false;
if (((x==null) && (y!=null))
|| (x!=null) && (y==null))
return false;
}
// Move on to the next row.
nextRow = new ArrayList<BTree>();
for (BTree tree : thisRow) {
nextRow.add((tree==null) ? null : tree.lt);
nextRow.add((tree==null) ? null : tree.rt);
}
boolean allNull = true;
for (BTree tree : nextRow) {
if (tree != null) allNull = false;
}
// If the row is all empty then we're done.
if (allNull) return true;
thisRow = nextRow;
}
}
これがgvijayごとのC++ソリューションです
bool isMirrorTree(BTnode* LP, BTnode* RP)
{
if (LP == NULL || RP == NULL) // if either is null check that both are NULL
{
return ( LP == NULL && RP == NULL );
}
// check that data is equal and then recurse
return LP->data == RP->data &&
isMirrorTree( LP->left, RP->right ) &&
isMirrorTree( LP->right, RP->left );
}
[〜#〜] edit [〜#〜]
コメントで指摘されたように、アルゴリズムの最初のバージョンは特定の入力に対して失敗しました。私は車輪を再発明するつもりはありません、私は単にPython @gvijay正しいアルゴリズムを使用して答えを提供します。最初に、二分木の表現:
class BTree(object):
def __init__(self, l, r, v):
self.left = l
self.right = r
self.value = v
def is_mirror(self):
return self._mirror_equals(self.left, self.right)
def _mirror_equals(self, left, right):
if left is None or right is None:
return left is None and right is None
return (left.value == right.value
and self._mirror_equals(left.left, right.right)
and self._mirror_equals(left.right, right.left))
コメントに記載されているように、問題のすべてのサンプルツリーおよび誤った結果を返しているツリーを使用して、上記のコードをテストしました。これで、すべてのケースで結果が正しくなりました。
root1 = BTree(
BTree(None, None, 2),
BTree(None, None, 2),
1)
root1.is_mirror() # True
root2 = BTree(
BTree(None, BTree(None, None, 3), 2),
BTree(None, None, 2),
1)
root2.is_mirror() # False
root3 = BTree(
BTree(
BTree(None, None, 4),
BTree(None, None, 3),
2),
BTree(
BTree(None, None, 3),
BTree(None, None, 4),
2),
1)
root3.is_mirror() # True
root4 = BTree(
BTree(
BTree(None, None, 3),
BTree(None, None, 4),
2),
BTree(
BTree(None, None, 3),
BTree(None, None, 4),
2),
1)
root4.is_mirror() # False
root5 = BTree(
BTree(BTree(None, None, 3), None, 2),
BTree(None, BTree(None, None, 3), 2),
1)
root5.is_mirror() # True
root6 = BTree(BTree(None, None, 1), None, 1)
root6.is_mirror() # False
root7 = BTree(BTree(BTree(None, None, 1), None, 2), None, 1)
root7.is_mirror() # False
誰かがSwiftバージョンを必要とする場合、ここにあります。
別のアプローチは、サブツリーの1つを単に反転し、2つの結果のサブツリーを簡単な方法で比較することです。
func compareTrees(left: TreeNode?, right: TreeNode?) -> Bool {
var res = false
if left == nil && right == nil {return true}
if left != nil && right != nil {
res = left!.val == right!.val &&
compareTrees(left!.left, right: right!.left) &&
compareTrees(left!.right, right: right!.right)
}
return res
}
func invertTree(node: TreeNode?) {
if node == nil {return}
var tmp = node!.left
node!.left = node!.right
node!.right = tmp
invertTree(node!.left)
invertTree(node!.right)
}
// and run it as:
if root == nil {print("Y")}
invertTree(root!.right)
compareTrees(root!.left, right: root!.right) ? print("Y") : print("N")
以下は、C-COdeに関するソリューションです。
isMirror(root)
{
Symmetric(root->left, root->right);
}
Symmetric(root1,root2)
{
if( (root1->left EX-NOR root2->right) && (root1->right EX-NOR root2->left) && (root1->value==root2->value) )
//exnor operation will return true if either both present or both not present
// a EX-NOR b =(!a && !b) || (a && b))
{
Symmetric(root1->left, root2->right);
Symmetric(root1->right, root2->left);
}
else return false;
}
パブリッククラスSymmetricTree {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//int[] array = {1,2,2,3,4,4,3};
/*
* 1
* / \
* / \
* / \
* 2 2
* / \ / \
* / \ / \
* 3 4 4 3
*
* */
//int[] array = {1,2};
BinaryTree bt=new BinaryTree();
bt.data=1;
bt.left = new BinaryTree(2);
bt.right = new BinaryTree(2);
bt.left.right = new BinaryTree(3);
bt.right.right = new BinaryTree(3);
//bt=BinaryTree.buildATree(bt, array);
System.out.print(isSymmetric(bt));
BinaryTree.inOrderTraversal(bt);
}
public static boolean isSymmetric(BinaryTree root){
if(root==null)
return true;
return isSymmetricLR(root.left,root.right);
}
public static boolean isSymmetricLR(BinaryTree left, BinaryTree right){
if(left == null && right == null)
return true;
if(left!=null && right!=null)
return (left.data == right.data) &&
(isSymmetricLR(left.left, right.right)) &&
(isSymmetricLR(left.right, right.left));
return false;
}
}
Pythonにソリューションを追加すると思いますが、これは他のアプローチよりも理解しやすい人もいるでしょう。アイデアは次のとおりです。
+1
を追加します。-1
を追加します。l+r
を親に返すしたがって、ツリー内の任意のノードのl+r == 0
の場合、そのノードに固定されているサブツリーは対称です。したがって、ツリー全体は、l+r == 0
がルートにある場合にのみ対称です。
def check(root):
l = check(root.left)+1 if root.left else 0
r = check(root.right)-1 if root.right else 0
return l+r
def is_symmetric(root):
return root is not None and check(root) == 0
pythonを使用して
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
def helper(root1, root2):
if not root1 and not root2: return True
if not root1 or not root2: return False
if root1.val != root2.val: return False
if helper(root1.left, root2.right): return helper(root1.right, root2.left)
return False
return helper(root, root)
少し異なるアプローチ。
文字列/配列などのデータ構造にすべてのコンテンツを保存するバイナリツリーを順方向にトラバーサルしてください。
走査が完了したら、配列内の要素が回文構造を形成しているかどうかを確認します。空間的には効率的ではありません(再帰はO(log(n))を取ります)、このメソッドはO(n))を示しますが、これも同様に機能します。
Pythonで少し異なるアプローチを使用した反復ソリューション。 queue1を使用して左の子を左から右の順に格納し、queue2を使用して右の子を右から左の順に格納し、等しいかどうかを比較します。
def isSymmetric(root):
if not root:
return True
if not (root.left or root.right):
return True
q1 = collections.deque([root.left])
q2 = collections.deque([root.right])
while q1 and q2:
n1 = q1.popleft()
n2 = q2.popleft()
if n1 is None and n2 is None:
continue
if (n1 is None) ^ (n2 is None):
return False
if n1.val != n2.val:
return False
q1.append(n1.left)
q1.append(n1.right)
q2.append(n2.right)
q2.append(n2.left)
if not (q1 and q2):
return True
return False