面试题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;
}