랜덤 포인터로 이진 트리 복제

난이도 하드
자주 묻는 질문 수행자 아마존 시스코 팩트 셋 광신자 구글 Microsoft 운영 Snapchat
해시 나무조회수 68

시스템 설계 면접 질문 너무 개방적이어서 올바른 준비 방법을 알기가 너무 어렵습니다. 이제 구매 후 Amazon, Microsoft 및 Adobe의 디자인 라운드를 해독할 수 있습니다. 이 책은. 매일 수정 하나 디자인 질문 그리고 나는 당신이 디자인 라운드를 깨뜨릴 수 있다고 약속합니다.

문제 정책

당신은 완전한 이진 트리 임의의 포인터로. 랜덤 포인터는 모든 노드가 왼쪽 및 오른쪽 자식이 아닌 다른 노드를 가리키는 노드를 참조합니다. 따라서 이것은 또한 간단한 이진 트리에서 노드의 표준 구조를 변경합니다. 이제 이진 트리의 노드는 현재 노드에 데이터를 저장하고 왼쪽, 오른쪽 및 임의 포인터에 대한 포인터를 저장합니다. 그래서 이제 우리는 문제가 무엇을 요구 하는가? "임의 포인터로 이진 트리 복제"문제는 주어진 초기 트리의 정확한 복사 본인 새 이진 트리를 만들도록 요청합니다. 따라서 새로 생성 된 트리에서 노드를 선택하면 왼쪽, 오른쪽 및 임의의 포인터가 원래 트리의 노드에 해당하는이 새 트리의 노드를 참조합니다.

입력

랜덤 포인터로 이진 트리 복제

Inorder traversal of original binary tree is [current node data, random pointer data]:
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

Inorder traversal of cloned binary tree is[current node data, random pointer data]:
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

설명

바이너리 트리의 왼쪽과 오른쪽 노드는 각 노드의 왼쪽과 오른쪽에 평소와 같이 표시됩니다. 그리고 다른 모든 포인터는 왼쪽 및 오른쪽 포인터가 임의의 포인터입니다. 일부 모서리에는 양방향 화살표가 있습니다. 노드의 부모에 대한 방향은 노드에 부모에 대한 임의의 포인터가 있음을 나타냅니다. 출력은 [현재 노드 데이터 / 임의 노드 데이터] 형식으로 제공됩니다.

해싱 접근법

따라서 우리는 초기 트리의 정확한 복사 본인 새 트리를 만들어야한다는 것을 알고 있습니다. inorder traversal을 실행하고 복사본을 만들 수 있습니다. 그러나 일부 노드가 아직 구성되지 않은 노드를 가리킬 수 있기 때문에 무작위 포인터 문제에 직면하게됩니다. 따라서이 오류를 제거합니다. 먼저 새 트리를 구성합니다. 그런 다음 해시맵 원래 트리의 각 노드에 해당하는 새 노드의 주소를 저장합니다. 따라서 다시 한 번 inorder traversal을 실행하고 HashMap에 값으로 저장되는 새 트리의 노드에 대한 임의의 포인터를 만듭니다.

효율적인 접근

위의 접근 방식에서 우리는 해시맵 원래 트리의 각 노드에 해당하는 복제 노드 주소를 저장했습니다. 그래서 그렇게하는 대신, 우리는 연결 목록 임의의 포인터로. 새로 생성 된 노드를 왼쪽 자식과 원래 트리의 해당 노드 사이에 밀어 넣습니다. 그래서 지금까지 초기 트리의 구조를 변경했습니다. 임의의 포인터를 설정하려면 노드에 해당하는 새 노드가 항상 왼쪽 자식이라는 것을 알고 있습니다. 따라서 입력 트리에서 노드의 왼쪽 자식에 무작위 포인터를 설정하기 만하면됩니다. 그러나 여전히 우리는 돌봐야 할 것이 하나 있습니다. 초기 및 복제 트리 노드의 왼쪽 자식을 복원해야합니다. 이 작업이 완료되면 무작위 포인터로 이진 트리를 복제했습니다.

암호

임의 포인터로 이진 트리를 복제하는 C ++ 코드

#include <iostream>
using namespace std;

struct node{
    int data;
  node *left, *right, *random;
};

node* create(int data){
  node* tmp = new node();
  tmp->data = data;
  tmp->left = tmp->right = tmp->random = NULL;
}

// print inorder traversal of the given tree in [node, random node] format
void inorder(node* root)
{
  if(root == NULL)
    return;
  // print inorder traversal of left tree
  inorder(root->left);
  // print in [current node, random node] format
  cout << "[" << root->data << " ";
  if (root->random == NULL)
    cout << "NULL], ";
  else
    cout << root->random->data << "], ";
  // print inorder traversal of right tree
  inorder(root->right);
}

// insert clone nodes between the original node and its left child
node* insertCloneNode(node* originalNode)
{
  if (originalNode == NULL)
    return NULL;

  node* left = originalNode->left;
  originalNode->left = create(originalNode->data);
  originalNode->left->left = left;
  if(left != NULL)
    left->left = insertCloneNode(left);

  originalNode->left->right = insertCloneNode(originalNode->right);
  return originalNode->left;
}

// sets the random pointers in clone tree
void setRandomNode(node* originalNode, node* cloneNode)
{
  if (originalNode == NULL)
    return;
  if(originalNode->random != NULL)
    cloneNode->random = originalNode->random->left;
  else
    cloneNode->random = NULL;

  if(originalNode->left != NULL && cloneNode->left != NULL)
    setRandomNode(originalNode->left->left, cloneNode->left->left);
  setRandomNode(originalNode->right, cloneNode->right);
}

// after all the work restore the left pointers in original and clone tree
void restoreTreeLeftNode(node* originalNode, node* cloneNode)
{
  if (originalNode == NULL)
    return;
  if (cloneNode->left != NULL)
  {
    node* cloneLeft = cloneNode->left->left;
    originalNode->left = originalNode->left->left;
    cloneNode->left = cloneLeft;
  }
  else
    originalNode->left = NULL;

  restoreTreeLeftNode(originalNode->left, cloneNode->left);
  restoreTreeLeftNode(originalNode->right, cloneNode->right);
}

// constructs the new clone tree
node* cloneTree(node* originalNode)
{
  if (originalNode == NULL)
    return NULL;
  node* cloneNode = insertCloneNode(originalNode);
  setRandomNode(originalNode, cloneNode);
  restoreTreeLeftNode(originalNode, cloneNode);
  return cloneNode;
}


int main()
{
  node *root = create(3);
  node* two = create(2);
  node* one = create(1);
  node* seven = create(7);
  node* five = create(5);
  node* nine = create(9);

  root->left = two;
  root->left->left = one;
  root->right = seven;
  root->right->left = five;
  root->right ->right = nine;

  root->random = nine;
  root->left->random = seven;
  root->left->left->random = two;
  root->right->random = one;
  root->right->left->random = one;
  root->right->right->random = five;

  cout << "Inorder traversal of original binary tree is [current node data, random pointer data]: \n";
  inorder(root);

  node *clone = cloneTree(root);

  cout << "\n\nInorder traversal of cloned binary tree is[current node data, random pointer data]: \n";
  inorder(clone);

  return 0;
}
Inorder traversal of original binary tree is [current node data, random pointer data]:
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

Inorder traversal of cloned binary tree is[current node data, random pointer data]:
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

임의 포인터로 이진 트리를 복제하는 Java 코드

import java.util.*;
// Class that denotes a node of the tree
class node
{ 
    int data; 
    node left, right, random; 
 
    public node(int data) 
    { 
        this.data = data;
        left = right = random = null; 
    } 
}
 
class Tree 
{ 
    static node root;
  static node create(int data) {
    node tmp = new node(data);
    return tmp;
  }
  // print inorder traversal of the given tree in [node, random node] format
  static void inorder(node root){
    if(root != null){
      // print inorder traversal of left tree
      inorder(root.left);
      // print in [current node, random node] format
      System.out.print("[" + root.data + " ");
      if(root.random == null)
        System.out.print("null], ");
      else
        System.out.print(root.random.data +"], ");
      // print inorder traversal of right tree
      inorder(root.right);
    }
  }
 
  // insert clone nodes between the original node and its left child
  static node insertCloneNode(node originalNode) 
  { 
    if (originalNode == null) 
      return null; 
 
    node left = originalNode.left; 
    originalNode.left = create(originalNode.data); 
    originalNode.left.left = left; 
    if(left != null) 
      left.left = insertCloneNode(left); 
 
    originalNode.left.right = insertCloneNode(originalNode.right); 
    return originalNode.left; 
  } 
 
  // sets the random pointers in clone tree
  static void setRandomNode(node originalNode, node cloneNode) 
  { 
    if (originalNode != null){
      if(originalNode.random != null) 
        cloneNode.random = originalNode.random.left; 
      else
        cloneNode.random = null; 
 
      if(originalNode.left != null && cloneNode.left != null) 
        setRandomNode(originalNode.left.left, cloneNode.left.left); 
      setRandomNode(originalNode.right, cloneNode.right); 
    }
  } 
 
  // after all the work restore the left pointers in original and clone tree
  static void restoreTreeLeftNode(node originalNode, node cloneNode) 
  { 
    if (originalNode != null) {
      if (cloneNode.left != null) 
      { 
        node cloneLeft = cloneNode.left.left; 
        originalNode.left = originalNode.left.left; 
        cloneNode.left = cloneLeft; 
      } 
      else
        originalNode.left = null; 
 
      restoreTreeLeftNode(originalNode.left, cloneNode.left); 
      restoreTreeLeftNode(originalNode.right, cloneNode.right); 
    }
  } 
 
  // constructs the new clone tree
  static node cloneTree(node originalNode) 
  { 
    if (originalNode == null)
      return null;
    node cloneNode = insertCloneNode(originalNode); 
    setRandomNode(originalNode, cloneNode); 
    restoreTreeLeftNode(originalNode, cloneNode); 
    return cloneNode; 
  } 
 
  public static void main(String[] args) {
    node root = create(3);
    node two = create(2);
    node one = create(1);
    node seven = create(7);
    node five = create(5);
    node nine = create(9);
 
    root.left = two;
    root.left.left = one;
    root.right = seven;
    root.right.left = five;
    root.right .right = nine;
 
    root.random = nine;
    root.left.random = seven;
    root.left.left.random = two;
    root.right.random = one;
    root.right.left.random = one;
    root.right.right.random = five;
 
    System.out.print("Inorder traversal of original binary tree is[current node data, random pointer data]: \n");
    inorder(root);
 
    node clone = cloneTree(root);
 
    System.out.print("\n\nInorder traversal of cloned binary tree is[current node data, random pointer data]: \n");
    inorder(clone);
  }
}
Inorder traversal of original binary tree is[current node data, random pointer data]: 
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5], 

Inorder traversal of cloned binary tree is[current node data, random pointer data]: 
[1 2], [2 7], [3 9], [5 1], [7 1], [9 5],

랜덤 포인터로 이진 트리를 복제하기위한 복잡성 분석

시간 복잡성 

의 위에), 우리는 이진 트리의 노드를 탐색했으며 이진 트리에는 N 개의 노드가 있기 때문입니다. 따라서 시간 복잡도는 선형입니다.

공간 복잡성

O (1), 배열이나지도에 정보를 저장하지 않았기 때문입니다. 따라서 공간 복잡성은 일정합니다.

균열 시스템 설계 인터뷰
Translate »