TIL/코딩인터뷰완전분석
[코딩인터뷰완전분석] 17일차. 트리와 그래프
NOHCODING
2023. 9. 26. 03:00
반응형
4.7 순서 정하기
import java.util.ArrayList;
import java.util.HashMap;
public class Project {
public enum State {COMPLETE, PARTIAL, BLANK};
private ArrayList<Project> children = new ArrayList<Project>();
private HashMap<String, Project> map = new HashMap<String, Project>();
private String name;
private State state = State.BLANK;
public Project(String n) {
name = n;
}
public String getName() {
return name;
}
public void addNeighbor(Project node) {
if (!map.containsKey(node.getName())) {
children.add(node);
map.put(node.getName(), node);
}
}
public State getState() {
return state;
}
public void setState(State st) {
state = st;
}
public ArrayList<Project> getChildren() {
return children;
}
}
4.8 첫 번째 공통 조상
이진 트리에서 노드가 두 개 주어졌을 때 이 두 노드의 첫번째 공통 조상을 찾는 알고리즘을 설계하고 그 코드를 작성해보자. 자료구조 내에 추가로 노드를 저장해두면 안된다.
import CtCILibrary.TreeNode;
public class Question {
static int TWO_NODES_FOUND = 2;
static int ONE_NODE_FOUND = 1;
static int NO_NODES_FOUND = 0;
// Checks how many 'special' nodes are located under this root
public static int covers(TreeNode root, TreeNode p, TreeNode q) {
int ret = NO_NODES_FOUND;
if (root == null) return ret;
if (root == p || root == q) ret += 1;
ret += covers(root.left, p, q);
if(ret == TWO_NODES_FOUND) // Found p and q
return ret;
return ret + covers(root.right, p, q);
}
public static TreeNode commonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (q == p && (root.left == q || root.right == q)) return root;
int nodesFromLeft = covers(root.left, p, q); // Check left side
if (nodesFromLeft == TWO_NODES_FOUND) {
if(root.left == p || root.left == q) return root.left;
else return commonAncestor(root.left, p, q);
} else if (nodesFromLeft == ONE_NODE_FOUND) {
if (root == p) return p;
else if (root == q) return q;
}
int nodesFromRight = covers(root.right, p, q); // Check right side
if(nodesFromRight == TWO_NODES_FOUND) {
if(root.right == p || root.right == q) return root.right;
else return commonAncestor(root.right, p, q);
} else if (nodesFromRight == ONE_NODE_FOUND) {
if (root == p) return p;
else if (root == q) return q;
}
if (nodesFromLeft == ONE_NODE_FOUND &&
nodesFromRight == ONE_NODE_FOUND) return root;
else return null;
}
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
TreeNode root = TreeNode.createMinimalBST(array);
TreeNode n3 = root.find(1);
TreeNode n7 = root.find(7);
TreeNode ancestor = commonAncestor(root, n3, n7);
System.out.println(ancestor.data);
}
}
4.9 BST 수열
배열의 원소를 왼쪽에서부터 차례로 트리에 삽입함으로써 이진 탐색 트리를 생성할 수 있다. 이진 탐색 트리 안에서 원소가 중복되지 않는다고 할 때, 해당 트리를 만들어 낼 수 있는 모든 가능한 배열을 출력하라.
import java.util.ArrayList;
import java.util.LinkedList;
import CtCILibrary.TreeNode;
public class Question {
public static void weaveLists(LinkedList<Integer> first, LinkedList<Integer> second, ArrayList<LinkedList<Integer>> results, LinkedList<Integer> prefix) {
/* One list is empty. Add the remainder to [a cloned] prefix and
* store result. */
if (first.size() == 0 || second.size() == 0) {
LinkedList<Integer> result = (LinkedList<Integer>) prefix.clone();
result.addAll(first);
result.addAll(second);
results.add(result);
return;
}
/* Recurse with head of first added to the prefix. Removing the
* head will damage first, so we’ll need to put it back where we
* found it afterwards. */
int headFirst = first.removeFirst();
prefix.addLast(headFirst);
weaveLists(first, second, results, prefix);
prefix.removeLast();
first.addFirst(headFirst);
/* Do the same thing with second, damaging and then restoring
* the list.*/
int headSecond = second.removeFirst();
prefix.addLast(headSecond);
weaveLists(first, second, results, prefix);
prefix.removeLast();
second.addFirst(headSecond);
}
public static ArrayList<LinkedList<Integer>> allSequences(TreeNode node) {
ArrayList<LinkedList<Integer>> result = new ArrayList<LinkedList<Integer>>();
if (node == null) {
result.add(new LinkedList<Integer>());
return result;
}
LinkedList<Integer> prefix = new LinkedList<Integer>();
prefix.add(node.data);
/* Recurse on left and right subtrees. */
ArrayList<LinkedList<Integer>> leftSeq = allSequences(node.left);
ArrayList<LinkedList<Integer>> rightSeq = allSequences(node.right);
/* Weave together each list from the left and right sides. */
for (LinkedList<Integer> left : leftSeq) {
for (LinkedList<Integer> right : rightSeq) {
ArrayList<LinkedList<Integer>> weaved = new ArrayList<LinkedList<Integer>>();
weaveLists(left, right, weaved, prefix);
result.addAll(weaved);
}
}
return result;
}
public static void main(String[] args) {
TreeNode node = new TreeNode(100);
int[] array = {100, 50, 20, 75, 150, 120, 170};
for (int a : array) {
node.insertInOrder(a);
}
ArrayList<LinkedList<Integer>> allSeq = allSequences(node);
for (LinkedList<Integer> list : allSeq) {
System.out.println(list);
}
System.out.println(allSeq.size());
}
}
4.10 하위 트리 확인
두 개의 커다란 이진트리가 T1과 T2가 있다고 하자. T1이 T2보다 훨씬 크다고 했을 때, T2가 T1인지 확인하는 알고리즘을 만들어보자
import CtCILibrary.AssortedMethods;
import CtCILibrary.TreeNode;
public class QuestionB {
public static boolean containsTree(TreeNode t1, TreeNode t2) {
if (t2 == null) {
return true; // The empty tree is a subtree of every tree.
}
return subTree(t1, t2);
}
/* Checks if the binary tree rooted at r1 contains the binary tree
* rooted at r2 as a subtree somewhere within it.
*/
public static boolean subTree(TreeNode r1, TreeNode r2) {
if (r1 == null) {
return false; // big tree empty & subtree still not found.
} else if (r1.data == r2.data && matchTree(r1,r2)) {
return true;
}
return subTree(r1.left, r2) || subTree(r1.right, r2);
}
/* Checks if the binary tree rooted at r1 contains the
* binary tree rooted at r2 as a subtree starting at r1.
*/
public static boolean matchTree(TreeNode r1, TreeNode r2) {
if (r1 == null && r2 == null) {
return true; // nothing left in the subtree
} else if (r1 == null || r2 == null) {
return false; // exactly one tree is empty, therefore trees don't match
} else if (r1.data != r2.data) {
return false; // data doesn't match
} else {
return matchTree(r1.left, r2.left) && matchTree(r1.right, r2.right);
}
}
public static void main(String[] args) {
// t2 is a subtree of t1
int[] array1 = {1, 2, 1, 3, 1, 1, 5};
int[] array2 = {2, 3, 1};
TreeNode t1 = AssortedMethods.createTreeFromArray(array1);
TreeNode t2 = AssortedMethods.createTreeFromArray(array2);
if (containsTree(t1, t2)) {
System.out.println("t2 is a subtree of t1");
} else {
System.out.println("t2 is not a subtree of t1");
}
// t4 is not a subtree of t3
int[] array3 = {1, 2, 3};
TreeNode t3 = AssortedMethods.createTreeFromArray(array1);
TreeNode t4 = AssortedMethods.createTreeFromArray(array3);
if (containsTree(t3, t4)) {
System.out.println("t4 is a subtree of t3");
} else {
System.out.println("t4 is not a subtree of t3");
}
}
}
4.12 합의 경로
각 노드의 값이 정수인 이진트리가 있다. 이때 정수의 합의 특정 값이 되도록 하는 경로의 개수를 세려고 한다. 경로가 루트에서 시작해서 말단 노드에서 끝날 필요는 없지만 반드시 아래로 내려가야한다. 즉, 부모 노드에서 자식 노드로만 움직일 수 있다.
import CtCILibrary.TreeNode;
public class QuestionA {
public static int countPathsWithSum(TreeNode root, int targetSum) {
if (root == null) return 0;
/* Count paths with sum starting from the root. */
int pathsFromRoot = countPathsWithSumFromNode(root, targetSum, 0);
/* Try the nodes on the left and right. */
int pathsOnLeft = countPathsWithSum(root.left, targetSum);
int pathsOnRight = countPathsWithSum(root.right, targetSum);
return pathsFromRoot + pathsOnLeft + pathsOnRight;
}
/* Returns the number of paths with this sum starting from this node. */
public static int countPathsWithSumFromNode(TreeNode node, int targetSum, int currentSum) {
if (node == null) return 0;
currentSum += node.data;
int totalPaths = 0;
if (currentSum == targetSum) { // Found a path from the root
totalPaths++;
}
totalPaths += countPathsWithSumFromNode(node.left, targetSum, currentSum); // Go left
totalPaths += countPathsWithSumFromNode(node.right, targetSum, currentSum); // Go right
return totalPaths;
}
public static void main(String [] args) {
/*
TreeNode root = new TreeNode(5);
root.left = new TreeNode(3);
root.right = new TreeNode(1);
root.left.left = new TreeNode(-8);
root.left.right = new TreeNode(8);
root.right.left = new TreeNode(2);
root.right.right = new TreeNode(6);
System.out.println(countPathsWithSum(root, 0));*/
/*TreeNode root = new TreeNode(-7);
root.left = new TreeNode(-7);
root.left.right = new TreeNode(1);
root.left.right.left = new TreeNode(2);
root.right = new TreeNode(7);
root.right.left = new TreeNode(3);
root.right.right = new TreeNode(20);
root.right.right.left = new TreeNode(0);
root.right.right.left.left = new TreeNode(-3);
root.right.right.left.left.right = new TreeNode(2);
root.right.right.left.left.right.left = new TreeNode(1);
System.out.println(countPathsWithSum(root, -14));*/
TreeNode root = new TreeNode(0);
root.left = new TreeNode(0);
root.right = new TreeNode(0);
root.right.left = new TreeNode(0);
root.right.left.right = new TreeNode(0);
root.right.right = new TreeNode(0);
System.out.println(countPathsWithSum(root, 0));
System.out.println(countPathsWithSum(root, 4));
}
}
반응형