面试题35:复杂链表的复制
题目:请实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表。在复杂链表中,每个结点除了有一个m_pNext指针指向下一个结点外,还有一个m_pSibling 指向链表中的任意结点或者nullptr。
public class Node { public int val; public Node next; public Node random; public Node(int val) { this.val = val; this.next = null; this.random = null; } }
public Node copyRandomList(Node head) { if (head == null) { return null; } // 细节:遍历时要以移动指针为准,以克隆指针为准容易在最后一个结点出幺蛾子 copyNodes(head); copyRandomPointer(head); return splitCopiedList(head); } private void copyNodes(Node head) { Node move = head; while (move != null) { Node cloneNode = new Node(move.val); cloneNode.next = move.next; move.next = cloneNode; move = cloneNode.next; } } private void copyRandomPointer(Node head) { Node move = head; while (move != null) { Node cloneNode = move.next; if (move.random != null) { cloneNode.random = move.random.next; } move = cloneNode.next; } } private Node splitCopiedList(Node head) { Node cloneHead = head.next; Node move = head; Node cloneNode = head.next; move.next = cloneNode.next; // 遍历时让move在cloneNode前面,保证原链表最后一个结点的next指向null move = move.next; while (move != null) { cloneNode.next = move.next; cloneNode = cloneNode.next; move.next = cloneNode.next; move = move.next; } return cloneHead; }
面试题36:二叉搜索树与双向链表
题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向循环链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
4 / \ 2 5 -> ==> 1 <=> 2 <=> 3 <=> 4 <=> 5 <== / \ || || 1 3 ||=============================||
public class Node { public int val; public Node left; public Node right; public Node() {} public Node(int _val) { val = _val; } public Node(int _val,Node _left,Node _right) { val = _val; left = _left; right = _right; } };
- 算法:
- 中序遍历
- 遍历左子树,获得并保存已经转换好部分的最后一个结点largestNode
- largestNode和当前遍历到的node进行连接并更新largestNode
- 继续使用largestNode遍历右子树
- 中序遍历
public Node treeToDoublyList(Node root) { if (root == null) { return null; } Node largestNode = null; largestNode = convertNode(root, largestNode); Node headNode = largestNode; while (headNode != null && headNode.left != null) { headNode = headNode.left; } largestNode.right = headNode; headNode.left = largestNode; return headNode; } private Node convertNode(Node node, Node largestNode) { if (node == null) { return largestNode; } if (node.left != null) { largestNode = convertNode(node.left, largestNode); } node.left = largestNode; if (largestNode != null) { largestNode.right = node; } largestNode = node; if (node.right != null) { largestNode = convertNode(node.right, largestNode); } return largestNode; }
面试题37:序列化二叉树
题目:请实现两个函数,分别用来序列化和反序列化二叉树。
- 算法:
- 前序遍历序列化(包括叶子节点的null子节点也要遍历)
- 前序遍历反序列化
// Encodes a tree to a single string. public String serialize(TreeNode root) { StringBuilder stringBuilder = new StringBuilder(); serialize(root, stringBuilder); return "["+stringBuilder.substring(0, stringBuilder.length()-1)+"]"; } private void serialize(TreeNode root, StringBuilder stringBuilder) { if (root == null) { stringBuilder.append("null,"); } else { stringBuilder.append(root.val+","); serialize(root.left, stringBuilder); serialize(root.right, stringBuilder); } } // Decodes your encoded data to tree. public TreeNode deserialize(String data) { data = data.substring(1, data.length()-1); String[] nodes = data.split(","); Queue<String> queue = new LinkedList<String>(); queue.addAll(Arrays.asList(nodes)); return deserialize(queue); } private TreeNode deserialize(Queue<String> queue) { String s = queue.poll(); if (s.equals("null")) { return null; } TreeNode root = new TreeNode(Integer.parseInt(s)); root.left = deserialize(queue); root.right = deserialize(queue); return root; }
- 算法:
- 队列
- 层次遍历
public String serialize(TreeNode root) { if (root == null) { return ""; } String output = ""; Queue<TreeNode> nodeQueue = new LinkedList<>(); nodeQueue.add(root); while(!nodeQueue.isEmpty()) { TreeNode node = nodeQueue.remove(); if (node == null) { output += "null, "; continue; } output += node.val + ", "; nodeQueue.add(node.left); nodeQueue.add(node.right); } return "[" + output.substring(0, output.length() - 2) + "]"; } public TreeNode deserialize(String input) { input = input.trim(); if (input.length() == 0) { return null; } input = input.substring(1, input.length() - 1); String[] parts = input.split(","); String item = parts[0]; TreeNode root = new TreeNode(Integer.parseInt(item)); Queue<TreeNode> nodeQueue = new LinkedList<>(); nodeQueue.add(root); int index = 1; while(!nodeQueue.isEmpty()) { TreeNode node = nodeQueue.remove(); if (index == parts.length) { break; } item = parts[index++]; item = item.trim(); if (!item.equals("null")) { int leftNumber = Integer.parseInt(item); node.left = new TreeNode(leftNumber); nodeQueue.add(node.left); } if (index == parts.length) { break; } item = parts[index++]; item = item.trim(); if (!item.equals("null")) { int rightNumber = Integer.parseInt(item); node.right = new TreeNode(rightNumber); nodeQueue.add(node.right); } } return root; }
面试题38:字符串的排列
题目:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。字符串可能包含重复字符,结果不能有重复排列。
public String[] permutation(String s) { if (s == null || s.length() == 0) { return new String[0]; } char[] chars = s.toCharArray(); HashSet<String> result = new HashSet<>(); permutation(chars, 0, result); String[] stringArray = new String[result.size()]; return result.toArray(stringArray); } private void permutation(char[] chars, int begin, HashSet<String> result) { if (begin == chars.length) { result.add(new String(chars)); } else { for (int i = begin; i < chars.length; i++) { swap(chars, i, begin); permutation(chars, begin+1, result); swap(chars, i, begin); } } } private void swap(char[] array, int x, int y) { char temp = array[x]; array[x] = array[y]; array[y] = temp; }