程序员面试金典(第 6 版)

程序员面试金典(第 6 版)

  • 面试题 01.01. 判定字符是否唯一
  • 面试题 01.02. 判定是否互为字符重排
  • 面试题 01.03. URL化
  • 面试题 01.04. 回文排列
  • 面试题 01.05. 一次编辑
  • 面试题 01.06. 字符串压缩
  • 面试题 01.07. 旋转矩阵
  • 面试题 01.08. 零矩阵
  • 面试题 01.09. 字符串轮转
  • 面试题 02.01. 移除重复节点
  • 面试题 02.02. 返回倒数第 k 个节点
  • 面试题 02.03. 删除中间节点
  • 面试题 02.04. 分割链表
  • 面试题 02.05. 链表求和
  • 面试题 02.06. 回文链表
  • 面试题 02.07. 链表相交
  • 面试题 02.08. 环路检测
  • 面试题 03.01. 三合一
  • 面试题 03.02. 栈的最小值
  • 面试题 03.03. 堆盘子
  • 面试题 03.04. 化栈为队
  • 面试题 03.05. 栈排序
  • 面试题 03.06. 动物收容所
  • 面试题 04.01. 节点间通路
  • 面试题 04.02. 最小高度树
  • 面试题 04.03. 特定深度节点链表
  • 面试题 04.04. 检查平衡性
  • 面试题 04.05. 合法二叉搜索树
  • 面试题 04.06. 后继者
  • 面试题 04.08. 首个共同祖先
  • 面试题 04.09. 二叉搜索树序列
  • 面试题 04.10. 检查子树
  • 面试题 04.12. 求和路径
  • 面试题 05.01. 插入
  • 面试题 05.03. 翻转数位
  • 面试题 05.04. 下一个数
  • 面试题 05.06. 整数转换
  • 面试题 05.07. 配对交换
  • 面试题 08.01. 三步问题
  • 面试题 08.02. 迷路的机器人
  • 面试题 08.03. 魔术索引
  • 面试题 08.04. 幂集
  • 面试题 08.06. 汉诺塔问题
  • 面试题 08.07. 无重复字符串的排列组合
  • 面试题 08.08. 有重复字符串的排列组合
  • 面试题 08.09. 括号
  • 面试题 08.10. 颜色填充
  • 面试题 08.11. 硬币
  • 面试题 08.12. 八皇后
  • 面试题 08.13. 堆箱子
  • 面试题 10.01. 合并排序的数组
  • 面试题 10.02. 变位词组
  • 面试题 10.03. 搜索旋转数组
  • 面试题 10.05. 稀疏数组搜索
  • 面试题 10.09. 排序矩阵查找
  • 面试题 10.11. 峰与谷
  • 面试题 16.01. 交换数字
  • 面试题 16.02. 单词频率
  • 面试题 16.04. 井字游戏
  • 面试题 16.05. 阶乘尾数
  • 面试题 16.06. 最小差
  • 面试题 16.07. 最大数值
  • 面试题 16.08. 整数的英语表示
  • 面试题 16.10. 生存人数
  • 面试题 16.11. 跳水板
  • 面试题 16.14. 最佳直线
  • 面试题 16.15. 珠玑妙算
  • 面试题 16.16. 部分排序
  • 面试题 16.17. 连续数列
  • 面试题 16.19. 水域大小
  • 面试题 16.20. T9键盘
  • 面试题 16.21. 交换和
  • 面试题 16.22. 兰顿蚂蚁
  • 面试题 16.24. 数对和
  • 面试题 16.25. LRU 缓存
  • 面试题 16.26. 计算器
  • 面试题 17.04. 消失的数字
  • 面试题 17.05. 字母与数字
  • 面试题 17.06. 2出现的次数
  • 面试题 17.08. 马戏团人塔
  • 面试题 17.09. 第 k 个数
  • 面试题 17.10. 主要元素
  • 面试题 17.11. 单词距离
  • 面试题 17.12. BiNode
  • 面试题 17.13. 恢复空格
  • 面试题 17.14. 最小K个数
  • 面试题 17.15. 最长单词
  • 面试题 17.16. 按摩师
  • 面试题 17.18. 最短超串
  • 面试题 17.19. 消失的两个数字
  • 面试题 17.20. 连续中值
  • 面试题 17.21. 直方图的水量
  • 面试题 17.22. 单词转换
  • 面试题 17.23. 最大黑方阵
  • 面试题 17.24. 最大子矩阵
  • 面试题 17.26. 稀疏相似度
  • 面试题19. 正则表达式匹配
  • 面试题32 - I. 从上到下打印二叉树

面试题 01.01. 判定字符是否唯一

程序员面试金典(第 6 版)_第1张图片

class Solution {
    public boolean isUnique(String astr) {
        if (astr == null || astr.length() <= 1) return true;
        boolean[] map = new boolean[26];
        for (char ch : astr.toCharArray()) {
            if (map[ch - 'a']) return false;
            map[ch - 'a'] = true;
        }
        return true;
    }
}

面试题 01.02. 判定是否互为字符重排

程序员面试金典(第 6 版)_第2张图片

class Solution {
    public boolean CheckPermutation(String s1, String s2) {
        if (s1 == null && s2 == null) return true;
        if (s1 == null || s2 == null || s1.length() != s2.length()) return false;
        int[] map = new int[26];
        for (char ch : s1.toCharArray()) {
            ++map[ch - 'a'];
        }
        for (char ch : s2.toCharArray()) {
            if (map[ch - 'a'] == 0) return false;
            --map[ch - 'a'];
        }
        return true;
    }
}

面试题 01.03. URL化

程序员面试金典(第 6 版)_第3张图片

class Solution {
    public String replaceSpaces(String S, int length) {
        if (S == null || S.length() == 0) return S;
        int num = 0;
        for (int i = 0; i < length; i++) {
            if (S.charAt(i) == ' ') {
                num++;
            }
        }
        char[] arr = new char[length + num * 2];
        int last = arr.length - 1, pre = length - 1;
        while (last >= 0) {
            if (S.charAt(pre) != ' ') arr[last--] = S.charAt(pre--);
            else {
                arr[last--] = '0';
                arr[last--] = '2';
                arr[last--] = '%';
                --pre;
            }
        }
        return new String(arr);
    }
}

面试题 01.04. 回文排列

程序员面试金典(第 6 版)_第4张图片

class Solution {
    public boolean canPermutePalindrome(String s) {
        if (s == null || s.length() <= 1) return true;
        boolean[] map = new boolean[256];
        for (char ch : s.toCharArray()) {
            map[ch] ^= true;
        }
        boolean flag = false;
        for (boolean b : map) {
            if (b) {
                if (flag) return false;
                flag = true;
            }
        }
        return true;
    }
}

面试题 01.05. 一次编辑

程序员面试金典(第 6 版)_第5张图片

  • oneEditAway(“teacher”,“lbeacher”)
class Solution {
    public boolean oneEditAway(String first, String second) {
        if (first.length() == 0 || second.length() == 0) return true;
        int subLen = first.length() - second.length();
        if (Math.abs(subLen) > 1) return false;
        int i = first.length() - 1, j = second.length() - 1;
        boolean flag = false;
        while (i >= 0 && j >= 0) {
            if (first.charAt(i) != second.charAt(j)) {
                if (subLen == -1) i++;// 阻止first-1
                else if (subLen == 1) j++;// 阻止second-1
                if (flag) return false;
                flag = true;
            }
            i--;
            j--;
        }
        return true;
    }
}

面试题 01.06. 字符串压缩

程序员面试金典(第 6 版)_第6张图片

class Solution {
    public String compressString(String S) {
        if (S == null || S.length() <= 1) return S;
        StringBuffer res = new StringBuffer();
        char[] arr = S.toCharArray();
        int pre = 0, N = arr.length;
        for (int i = 1; i < N; i++) {
            if (arr[i] != arr[i - 1]) {
                res.append(arr[i - 1]);
                res.append(i - pre);
                pre = i;
            }
        }
        res.append(arr[N - 1]);
        res.append(N - pre);
        return res.length() >= N ? S : res.toString();
    }
}

面试题 01.07. 旋转矩阵

程序员面试金典(第 6 版)_第7张图片

class Solution {
    public void rotate(int[][] matrix) {
        if (matrix.length <= 1) return;
        int firstRow = 0, firstLine = 0, secondRow = matrix.length - 1, secondLine = matrix[0].length - 1;
        while (firstLine < secondLine && firstRow < secondRow) {
            circleSway(matrix, firstRow++, firstLine++, secondRow--, secondLine--);
        }
        for (int[] a : matrix) System.out.println(Arrays.toString(a));
    }

    private void circleSway(int[][] matrix, int locR1, int locL1, int locR2, int locL2) {
        for (int i = 0; i < locL2 - locL1; i++) {
            int temp = matrix[locR1][locL1 + i];
            matrix[locR1][locL1 + i] = matrix[locR2 - i][locL1];
            matrix[locR2 - i][locL1] = matrix[locR2][locL2 - i];
            matrix[locR2][locL2 - i] = matrix[locR1 + i][locL2];
            matrix[locR1 + i][locL2] = temp;
        }
    }
}

面试题 01.08. 零矩阵

程序员面试金典(第 6 版)_第8张图片

class Solution {
    public void setZeroes(int[][] matrix) {
        if (matrix == null) return;
        int M = matrix.length, N = matrix[0].length;
        boolean[] rows = new boolean[M], lines = new boolean[N];
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                if (matrix[i][j] == 0) {
                    rows[i] = true;
                    lines[j] = true;
                }
            }
        }
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                if (rows[i] || lines[j]) {
                    matrix[i][j] = 0;
                }
            }
        }
    }
}

面试题 01.09. 字符串轮转

程序员面试金典(第 6 版)_第9张图片

class Solution {
    public boolean isFlipedString(String s1, String s2) {
        if (s1 == null && s2 == null) return true;
        if (s1 == null || s2 == null) return false;
        if (s1.length() != s2.length()) return false;
        String s = s1 + s1;
        return s.contains(s2);
    }
}

面试题 02.01. 移除重复节点

程序员面试金典(第 6 版)_第10张图片

class Solution {
    public ListNode removeDuplicateNodes(ListNode head) {
        if (head == null || head.next == null) return head;
        BitSet set = new BitSet();
        ListNode tail = head;
        set.set(head.val, true);
        while (tail.next != null) {
            if (!set.get(tail.next.val)) {
                set.set(tail.next.val, true);
                tail = tail.next;
            } else {
                tail.next = tail.next.next;
            }
        }
        return head;
    }
}

面试题 02.02. 返回倒数第 k 个节点

程序员面试金典(第 6 版)_第11张图片

class Solution {
    public int kthToLast(ListNode head, int k) {
        ListNode tail = head;
        for (int i = 0; i < k; i++) {
            tail = tail.next;
        }
        ListNode res = head;
        while (tail != null) {
            tail = tail.next;
            res = res.next;
        }
        return res.val;
    }
}

面试题 02.03. 删除中间节点

在这里插入图片描述

class Solution {
    public void deleteNode(ListNode node) {
        node.val=node.next.val;
        node.next=node.next.next;
    }
}

面试题 02.04. 分割链表

程序员面试金典(第 6 版)_第12张图片

  • 交换后忘置空,注意是next.val,不要判断错
class Solution {
    public ListNode partition(ListNode head, int x) {
        if (head == null || head.next == null) return head;
        ListNode small = new ListNode(), fast = new ListNode();
        small.next = head;
        ListNode smallTail = small, fastTail = fast;
        while (smallTail.next != null) {
            if (smallTail.next.val >= x) {
                fastTail.next = smallTail.next;
                fastTail=fastTail.next;
                smallTail.next = smallTail.next.next;
                fastTail.next=null;
            }else {
                smallTail=smallTail.next;
            }
        }
        smallTail.next = fast.next;
        return small.next;
    }
}

面试题 02.05. 链表求和

程序员面试金典(第 6 版)_第13张图片

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if (l1 == null || l2 == null) return l1 == null ? l2 : l1;
        ListNode tail1 = l1, tail2 = l2;
        int pre = 0;// 进位
        if (l1.val + l2.val >= 10) {
            l1.val = l1.val + l2.val - 10;
            pre = 1;
        } else {
            l1.val = l1.val + l2.val;
        }
        while (tail1.next != null && tail2.next != null) {
            if (tail1.next.val + tail2.next.val + pre >= 10) {
                tail1.next.val = tail1.next.val + tail2.next.val + pre - 10;
                pre = 1;
            } else {
                tail1.next.val = tail1.next.val + tail2.next.val + pre;
                pre = 0;
            }
            tail1 = tail1.next;
            tail2 = tail2.next;
        }
        if (tail2.next != null) tail1.next = tail2.next;// 都连到l1上
        if (pre == 0) return l1;
        while (tail1.next != null && pre == 1) {// 处理l1上的一个链表的进位
            if (tail1.next.val + pre >= 10) {
                tail1.next.val = 0;
                pre = 1;
            } else {
                tail1.next.val++;
                pre = 0;
            }
            tail1 = tail1.next;
        }
        if (tail1.next == null && pre == 1) {// 是否出现新高位
            tail1.next = new ListNode(1);
        }
        return l1;
    }
}

面试题 02.06. 回文链表

程序员面试金典(第 6 版)_第14张图片

class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null) return true;
        ListNode fastNode = head;
        ListNode slowNode = head;
        while (fastNode.next != null && fastNode.next.next != null) {
            fastNode = fastNode.next.next;
            slowNode = slowNode.next;
        }
        slowNode = slowNode.next;
        fastNode = null;
        while (slowNode != null) {
            ListNode nextnode = slowNode.next;
            slowNode.next = fastNode;
            fastNode = slowNode;
            slowNode = nextnode;
        }
        while (fastNode != null) {
            if (head.val != fastNode.val) return false;
            fastNode = fastNode.next;
            head = head.next;
        }
        return true;
    }
}

面试题 02.07. 链表相交

程序员面试金典(第 6 版)_第15张图片

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return null;
        int N = 0;
        ListNode tail = headA,pre;
        while (tail.next != null) {
            N++;
            tail = tail.next;
        }
        tail = headB;
        while (tail.next != null) {
            N--;
            tail = tail.next;
        }
        if (N < 0) {
            pre = headB;
            tail = headA;
            N = -N;
        } else {
            pre = headA;
            tail = headB;
        }
        while (N-- > 0) pre = pre.next;
        while (pre != tail) {
            pre = pre.next;
            tail = tail.next;
        }
        return pre;
    }
}

面试题 02.08. 环路检测

程序员面试金典(第 6 版)_第16张图片

class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null) return null;
        ListNode slow = head;
        ListNode quick = head;
        boolean flag = false;
        while (quick.next != null && quick.next.next != null) {
            slow = slow.next;
            quick = quick.next.next;
            if (slow == quick) {
                flag = true;
                break;
            }
        }
        if (!flag) return null;
        quick = head;
        while (quick != slow) {
            quick = quick.next;
            slow = slow.next;
        }
        return slow;
    }
}

面试题 03.01. 三合一

程序员面试金典(第 6 版)_第17张图片

class TripleInOne {
    private int[] arr = {};
    private int[] size = {};
    private int stackSize;
    public TripleInOne(int stackSize) {
        this.stackSize = stackSize;
        // 第一个栈 [0*stackSize, 1*stackSize),第二个栈 [1*stackSize, 2*stackSize),第三个栈 [2*stackSize, 3*stackSize)
        arr = new int[3*stackSize];
        size = new int[] {0, 0, 0};
    }
    
    public void push(int stackNum, int value) {
        int length = size[stackNum];
        if (length < stackSize) {
            arr[stackNum*stackSize+length] = value;
            size[stackNum] = length + 1;
        }
    }
    
    public int pop(int stackNum) {
        int topVal = peek(stackNum);
        if (size[stackNum] > 0)
            size[stackNum] -= 1;
        return topVal;
    }
    
    public int peek(int stackNum) {
        if (size[stackNum] == 0)
            return -1;
        return arr[stackNum*stackSize+size[stackNum]-1];
    }
    
    public boolean isEmpty(int stackNum) {
        return size[stackNum] == 0;
    }
}

面试题 03.02. 栈的最小值

程序员面试金典(第 6 版)_第18张图片

public class MinStack {

    // 数据栈
    private Stack<Integer> data;
    // 辅助栈
    private Stack<Integer> helper;
    public MinStack() {
        data = new Stack<>();
        helper = new Stack<>();
    }

    // 思路 2:辅助栈和数据栈不同步
    // 关键 1:辅助栈的元素空的时候,必须放入新进来的数
    // 关键 2:新来的数小于或者等于辅助栈栈顶元素的时候,才放入(特别注意这里等于要考虑进去)
    // 关键 3:出栈的时候,辅助栈的栈顶元素等于数据栈的栈顶元素,才出栈,即"出栈保持同步"就可以了

    public void push(int x) {
        // 辅助栈在必要的时候才增加
        data.add(x);
        // 关键 1 和 关键 2
        if (helper.isEmpty() || helper.peek() >= x) {
            helper.add(x);
        }
    }

    public void pop() {
        // 关键 3:data 一定得 pop()
        if (!data.isEmpty()) {
            // 注意:声明成 int 类型,这里完成了自动拆箱,从 Integer 转成了 int,因此下面的比较可以使用 "==" 运算符
            int top = data.pop();
            if(top == helper.peek()){
                helper.pop();
            }
        }
    }

    public int top() {
        if(!data.isEmpty()){
            return data.peek();
        }
        throw new RuntimeException("栈中元素为空,此操作非法");
    }

    public int getMin() {
        if(!helper.isEmpty()){
            return helper.peek();
        }
        throw new RuntimeException("栈中元素为空,此操作非法");
    }

}

面试题 03.03. 堆盘子

程序员面试金典(第 6 版)_第19张图片

class StackOfPlates {

    private List<Stack<Integer>> stackList;
    private int cap;

    public StackOfPlates(int cap) {
        stackList = new ArrayList<>();
        this.cap = cap;
    }

    public void push(int val) {
        if (cap <= 0) return;
        if (stackList.isEmpty() || stackList.get(stackList.size() - 1).size() == cap) {
            Stack<Integer> stack = new Stack<>();
            stack.push(val);
            stackList.add(stack);
            return;
        }
        stackList.get(stackList.size() - 1).push(val);
    }

    public int pop() {
        return popAt(stackList.size() - 1);
    }

    public int popAt(int index) {
        if (index < 0 || index >= stackList.size()) return -1;
        Stack<Integer> stack = stackList.get(index);
        int res = stack.pop();
        if (stack.isEmpty()) stackList.remove(index);
        return res;
    }
}

面试题 03.04. 化栈为队

程序员面试金典(第 6 版)_第20张图片

class MyQueue {
    Stack<Integer> addStack = new Stack<>();
    Stack<Integer> delStack = new Stack<>();

    /**
     * Initialize your data structure here.
     */
    public MyQueue() {

    }

    /**
     * Push element x to the back of queue.
     */
    public void push(int x) {
        addStack.push(x);
    }

    /**
     * Removes the element from in front of queue and returns that element.
     */
    public int pop() {
        if (!delStack.isEmpty()) return delStack.pop();
        if (addStack.isEmpty()) return -1;
        while (!addStack.isEmpty()) delStack.add(addStack.pop());
        return delStack.pop();
    }

    /**
     * Get the front element.
     */
    public int peek() {
        if (!delStack.isEmpty()) return delStack.peek();
        if (addStack.isEmpty()) return -1;
        while (!addStack.isEmpty()) delStack.add(addStack.pop());
        return delStack.peek();
    }

    /**
     * Returns whether the queue is empty.
     */
    public boolean empty() {
        return ( addStack.isEmpty() && delStack.isEmpty() );// 有括号效率更高,不知道为啥
    }
}

面试题 03.05. 栈排序

程序员面试金典(第 6 版)_第21张图片

class SortedStack {

    Deque<Integer> minStack = new LinkedList<>(); // 维护一个单调递增(sort in acending)/递减栈(sort in decending)
    Deque<Integer> tempStack = new LinkedList<>(); // 辅助栈

    public SortedStack() {
    }

    public void push(int val) {
        while (!minStack.isEmpty() && minStack.peek() < val) tempStack.push(minStack.pop());
        minStack.push(val);
        while (!tempStack.isEmpty()) minStack.push(tempStack.pop());
    }

    public void pop() {
        if (!isEmpty()) minStack.pop();
    }

    public int peek() {
        return minStack.isEmpty() ? -1 : minStack.peek();
    }

    public boolean isEmpty() {
        return minStack.isEmpty();
    }
}

面试题 03.06. 动物收容所

程序员面试金典(第 6 版)_第22张图片

class AnimalShelf {
    Deque<int[]> cat;
    Deque<int[]> dog;
    public AnimalShelf() {
        cat = new ArrayDeque<>();
        dog = new ArrayDeque<>();
    }
    
    public void enqueue(int[] animal) {
        if(animal[1] == 0) cat.add(animal);
        else dog.add(animal);
    }
    
    public int[] dequeueAny() {
        if(cat.isEmpty() && dog.isEmpty()) return new int[]{-1,-1};
        if(cat.isEmpty()) return dog.poll();
        if(dog.isEmpty()) return cat.poll();
        if(cat.peek()[0] < dog.peek()[0]) return cat.poll();
        return dog.poll();
    }
    
    public int[] dequeueDog() {
        if(dog.isEmpty()) return new int[]{-1,-1};
        return dog.poll();
    }
    
    public int[] dequeueCat() {
        if(cat.isEmpty()) return new int[]{-1,-1};
        return cat.poll();
    }
}

面试题 04.01. 节点间通路

程序员面试金典(第 6 版)_第23张图片

class Solution {
    public boolean findWhetherExistsPath(int n, int[][] graph, int start, int target) {
        if (graph == null || graph.length == 0) return false;
        ArrayList<LinkedList<Integer>> list = new ArrayList<>(n);
        for (int i = 0; i < n; i++) {
            list.add(new LinkedList<>());
        }
        for (int[] val : graph) {
            list.get(val[0]).add(val[1]);
        }
        boolean[] isvisited = new boolean[n];
        Queue<Integer> queue = new LinkedList<>();
        queue.add(start);
        isvisited[start] = true;
        while (!queue.isEmpty()) {
            int x = queue.poll();
            if (x == target) return true;
            for (int next : list.get(x)) {
                if (!isvisited[next]) {
                    queue.add(next);
                    isvisited[next] = true;
                }

            }
        }
        return false;
    }
}

面试题 04.02. 最小高度树

程序员面试金典(第 6 版)_第24张图片

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        if (nums == null || nums.length == 0) return null;
        return process(nums, 0, nums.length - 1);
    }

    private TreeNode process(int[] nums, int left, int right) {
        if (left > right) return null;
        int mid = (left + right) / 2;
        TreeNode x = new TreeNode(nums[mid]);
        x.left = process(nums, left, mid - 1);
        x.right = process(nums, mid + 1, right);
        return x;
    }
}

面试题 04.03. 特定深度节点链表

程序员面试金典(第 6 版)_第25张图片

class Solution {
    public ListNode[] listOfDepth(TreeNode tree) {
        if (tree == null) return null;
        Queue<TreeNode> queue = new LinkedList<>();
        ArrayList<ListNode> res = new ArrayList<>();
        res.add(new ListNode(tree.val));
        ListNode head = new ListNode();
        ListNode tail = head;
        TreeNode thisLast = tree, nextLast = null;
        queue.add(tree);
        while (!queue.isEmpty()) {
            TreeNode x = queue.poll();
            if (x.left != null) {
                queue.add(x.left);
                tail.next = new ListNode(x.left.val);
                tail = tail.next;
                nextLast = x.left;
            }
            if (x.right != null) {
                queue.add(x.right);
                tail.next = new ListNode(x.right.val);
                tail = tail.next;
                nextLast = x.right;
            }
            if (x == thisLast) {
                if (head.next!=null)res.add(head.next);
                head = new ListNode();
                tail = head;
                thisLast = nextLast;
                nextLast = null;
            }
        } 
        return res.toArray(new ListNode[0]);
    }
}

面试题 04.04. 检查平衡性

程序员面试金典(第 6 版)_第26张图片

class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) return true;
        return process(root).is;
    }

    public transData process(TreeNode x) {
        if (x == null) return new transData(0, true);
        transData l = process(x.left), r = process(x.right);
        if (!l.is || !r.is || Math.abs(l.height - r.height) > 1) return new transData(-1, false);
        return new transData(Math.max(l.height, r.height) + 1, true);
    }

    static class transData {
        int height;
        boolean is;
        public transData(int _height, boolean _is) {
            height = _height;
            is = _is;
        }
    }
}

面试题 04.05. 合法二叉搜索树

程序员面试金典(第 6 版)_第27张图片

class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    private boolean isValidBST(TreeNode root, long min, long max) {
        return root == null ||
                (root.val > min && root.val < max &&
                        isValidBST(root.left, min, root.val) && 
                        	isValidBST(root.right, root.val, max));
    }
}

面试题 04.06. 后继者

程序员面试金典(第 6 版)_第28张图片

class Solution {
    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        if (root == null) {
            return null;
        }
        // 当前节点值小于等于目标值,那么当前目标值的后继者必然在右子树
        if (p.val >= root.val) {
            return inorderSuccessor(root.right, p);
        }
        // 否则结果有可能是当前节点,或者在当前节点的左子树中
        // 那么先去左子树找一下试试,找不到的话返回当前节点即是结果
        TreeNode node = inorderSuccessor(root.left, p);
        return node == null ? root : node;
    }
}

面试题 04.08. 首个共同祖先

程序员面试金典(第 6 版)_第29张图片

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || root == p || root == q) return root;
        TreeNode l = lowestCommonAncestor(root.left, p, q);
        TreeNode r = lowestCommonAncestor(root.right, p, q);
        if (l != null && r != null) return root;
        return l == null ? r : l;
    }
}

面试题 04.09. 二叉搜索树序列

程序员面试金典(第 6 版)_第30张图片

class Solution {
    List<List<Integer>> res = new LinkedList<>();
    public List<List<Integer>> BSTSequences(TreeNode root) {
        if (root == null)  {
            res.add(new LinkedList<>());
            return res;
        }
        LinkedList<Integer> path = new LinkedList<>();
        path.add(root.val);
        helper(root, new LinkedList<>(), path);
        return res;
    }
    public void helper(TreeNode root, LinkedList<TreeNode> queue, LinkedList<Integer> path) {
        if (root == null) return;
        if (root.left != null) queue.add(root.left);
        if (root.right != null) queue.add(root.right);
        if (queue.isEmpty()) {
            res.add(new LinkedList<>(path));
            return;
        }
        int lens = queue.size();
        for (int i = 0; i < lens; i++) {
            TreeNode cur = queue.get(i);
            queue.remove(i);
            path.add(cur.val);
            helper(cur, new LinkedList<>(queue), path);
            queue.add(i, cur);
            path.removeLast();
        }
    }
}

面试题 04.10. 检查子树

程序员面试金典(第 6 版)_第31张图片

class Solution {
    public boolean checkSubTree(TreeNode t1, TreeNode t2) {
        if (t2 == null) return true;
        if (t1 == null) return false;
        boolean flag = false;
        if (t1.val == t2.val) flag = helperCompareTree(t1, t2);
        if (!flag) flag = checkSubTree(t1.left, t2);
        if (!flag) flag = checkSubTree(t1.right, t2);
        return flag;
    }

    private boolean helperCompareTree(TreeNode t1, TreeNode t2) {
        if (t2 == null) return true;
        if (t1 == null) return false;
        if (t1.val != t2.val) return false;
        return helperCompareTree(t1.left, t2.left) && helperCompareTree(t1.right, t2.right);
    }
}

面试题 04.12. 求和路径

程序员面试金典(第 6 版)_第32张图片

class Solution {
    public int pathSum(TreeNode root, int sum) {
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 1);
        return helper(root, map, sum, 0);
    }

    private int helper(TreeNode node, Map<Integer, Integer> prefixSum, int sum, int curSum) {
        if (node == null) {
            return 0;
        }
        curSum += node.val;
        int count = prefixSum.getOrDefault(curSum - sum, 0);
        prefixSum.put(curSum, prefixSum.getOrDefault(curSum, 0) + 1);
        count += helper(node.left, prefixSum, sum, curSum);
        count += helper(node.right, prefixSum, sum, curSum);
        prefixSum.put(curSum, prefixSum.getOrDefault(curSum, 0) - 1);
        return count;
    }
}

面试题 05.01. 插入

程序员面试金典(第 6 版)_第33张图片

class Solution {
    public int insertBits(int N, int M, int i, int j) {
        int k = 1 << i;
        M <<= i;
        while (i++ <= j) {
            N &= ~k;
            k <<= 1;
        }
        return M|N;
    }
}

面试题 05.03. 翻转数位

程序员面试金典(第 6 版)_第34张图片

class Solution {
    public int reverseBits(int num) {
        int maxLen = 0, preLen = 0, curLen = 0, bits = 32;
        while (bits-- > 0) {
            if ((num & 1) == 0) {// 当前位为零
                curLen -= preLen;// 减去前驱
                preLen = curLen + 1;// 更新前驱
            }
            curLen++;// 为1就加一,为零使用反转后加一
            maxLen = Math.max(maxLen, curLen);
            num >>= 1;
        }
        return maxLen;
    }
}

面试题 05.04. 下一个数

程序员面试金典(第 6 版)_第35张图片
程序员面试金典(第 6 版)_第36张图片

class Solution {
    public int[] findClosedNumbers(int num) {
        if (num == 1) return new int[]{2, -1};
        if (num == 2147483647) return new int[]{-1, -1};
        int MAX = nextMax(num);
        int MIN = ~nextMax(~num);
        if (MAX < 0) MAX = -1;
        return new int[]{MAX, MIN};
    }

    int nextMax(int num) {
        int x = num & -num;
        int y = x + num;
        return  ((num & ~y) / x >> 1 | y);
    }
}

面试题 05.06. 整数转换

程序员面试金典(第 6 版)_第37张图片

class Solution {
    public int convertInteger(int A, int B) {
        int C = A ^ B, res = 0;
        while (C != 0) {
            C &= (C - 1);
            ++res;
        }
        return res;
    }
}

面试题 05.07. 配对交换

程序员面试金典(第 6 版)_第38张图片

class Solution {
    public int exchangeBits(int num) {
        return (num & 0x55555555) << 1 | (num & 0xAAAAAAAA) >> 1;
    }
}

面试题 08.01. 三步问题

程序员面试金典(第 6 版)_第39张图片

class Solution {
    public int waysToStep(int n) {
        if (n == 1) return 1;
        if (n == 2) return 2;
        if (n == 3) return 4;
        long a = 1, b = 1, c = 2, d = 0;
        for (int i = n - 3; i >= 0; i--) {
            d =( a + b + c) % 1000000007;
            a = b;
            b = c;
            c = d;
        }
        return (int) (d % 1000000007);
    }
}

面试题 08.02. 迷路的机器人

程序员面试金典(第 6 版)_第40张图片

class Solution {
    LinkedList<List<Integer>> res = new LinkedList<>();
    boolean[][] isvisited;
    int M, N;

    public List<List<Integer>> pathWithObstacles(int[][] obstacleGrid) {
        M = obstacleGrid.length;
        N = obstacleGrid[0].length;
        isvisited = new boolean[M][N];
        dfs(obstacleGrid, 0, 0);
        return res;
    }

    private boolean dfs(int[][] obstacleGrid, int i, int j) {
        if (i < 0 || i >= M || j < 0 || j >= N || obstacleGrid[i][j] == 1 || isvisited[i][j]) return false;
        res.addLast(Arrays.asList(i, j));
        if (i == M - 1 && j == N - 1) return true;
        isvisited[i][j] = true;
        if (dfs(obstacleGrid, i + 1, j)) return true;
        if (dfs(obstacleGrid, i, j + 1)) return true;
        res.removeLast();
        return false;
    }
}

面试题 08.03. 魔术索引

程序员面试金典(第 6 版)_第41张图片

class Solution {
    public int findMagicIndex(int[] nums) {
        for(int i=0;i<nums.length; ){
            if(nums[i]==i)
                return i;
            i=Math.max(nums[i],i+1);
        }
        return -1;
    }
}

面试题 08.04. 幂集

程序员面试金典(第 6 版)_第42张图片

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();

    public List<List<Integer>> subsets(int[] nums) {
        if (nums == null || nums.length == 0) return res;
        backtrack(0, nums);
        return res;
    }

    private void backtrack(int index, int[] nums) {
        res.add(new ArrayList<>(path));// new ArrayList<>比较快
        for (int i = index; i < nums.length; i++) {
            path.addLast(nums[i]);
            backtrack(i + 1, nums);
            path.removeLast();
        }
    }
}

面试题 08.06. 汉诺塔问题

程序员面试金典(第 6 版)_第43张图片

class Solution {
    public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
        int n = A.size();
        move(n, A, B, C);
    }

    void move(int n, List<Integer> A, List<Integer> B, List<Integer> C) {
        if (n == 1) {
            C.add(A.remove(A.size() - 1));
            return;
        }
        move(n - 1, A, C, B);    // 将A上面n-1个通过C移到B
        // 将A最后一个移到C
        C.add(A.remove(A.size() - 1));         // 这时,A空了
        move(n - 1, B, A, C);     // 将B上面n-1个通过空的A移到C
    }
}

面试题 08.07. 无重复字符串的排列组合

程序员面试金典(第 6 版)_第44张图片

class Solution {
    ArrayList<String> res = new ArrayList<>();
    StringBuffer sb = new StringBuffer();
    char[] arr;
    boolean[] isvisited;

    public String[] permutation(String S) {
        if (S == null || S.length() == 0) return res.toArray(new String[0]);
        isvisited = new boolean[S.length()];
        arr = S.toCharArray();
        backtrack(0);
        return res.toArray(new String[0]);
    }

    private void backtrack(int i) {
        if (i == arr.length) {
            res.add(sb.toString());
            return;
        }
        for (int n = 0; n < arr.length; n++) {
            if (!isvisited[n]) {
                isvisited[n] = true;
                sb.append(arr[n]);
                backtrack(i + 1);
                isvisited[n] = false;
                sb.deleteCharAt(sb.length() - 1);
            }
        }
    }
}

面试题 08.08. 有重复字符串的排列组合

程序员面试金典(第 6 版)_第45张图片

class Solution {
    ArrayList<String> res = new ArrayList<>();
    StringBuffer sb = new StringBuffer();
    char[] arr;
    boolean[] isvisited;

    public String[] permutation(String S) {
        if (S == null || S.length() == 0) return res.toArray(new String[0]);
        isvisited = new boolean[S.length()];
        arr = S.toCharArray();
        Arrays.sort(arr);
        backtrack(0);
        return res.toArray(new String[0]);
    }

    private void backtrack(int i) {
        if (sb.length() == arr.length) {
            res.add(sb.toString());
            return;
        }
        for (int n = 0; n < arr.length; n++) {
            if (n > 0 && arr[n] == arr[n - 1] && !isvisited[n - 1]) continue;
            if (!isvisited[n]) {
                isvisited[n] = true;
                sb.append(arr[n]);
                backtrack(i + 1);
                isvisited[n] = false;
                sb.deleteCharAt(sb.length() - 1);
            }
        }
    }
}

面试题 08.09. 括号

程序员面试金典(第 6 版)_第46张图片

class Solution {
    List<String> list = new ArrayList<String>();
    int N;
    StringBuffer s = new StringBuffer("");

    public List<String> generateParenthesis(int n) {
        N = n;
        process(0, 0);
        return list;
    }

    private void process(int i, int j) {
        if (j == N) {
            list.add(s.toString());
            return;
        }
        if (i < N) {
            s.append("(");
            process(i + 1, j);
            s.deleteCharAt(i + j);
        }
        if (j < i) {
            s.append(")");
            process(i, j + 1);
            s.deleteCharAt(i + j);
        }
    }
}

面试题 08.10. 颜色填充

程序员面试金典(第 6 版)_第47张图片

class Solution {
    public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
        helper(image, sr, sc, image[sr][sc], newColor);
        return image;
    }
    private void helper(int[][] image, int i, int j, int oldColor, int newColor){
        if(i < 0 || i >= image.length || j < 0 || j >= image[0].length || image[i][j] != oldColor || image[i][j] == newColor) return;
        image[i][j] = newColor;
        helper(image, i+1, j, oldColor, newColor);
        helper(image, i-1, j, oldColor, newColor);
        helper(image, i, j+1, oldColor, newColor);
        helper(image, i, j-1, oldColor, newColor);
    }
}

面试题 08.11. 硬币

程序员面试金典(第 6 版)_第48张图片

class Solution {
    static final int MOD = 1000000007;

    public int waysToChange(int n) {
        int ans = 0;
        for (int i = 0; i * 25 <= n; ++i) {
            int rest = n - i * 25;
            int a = rest / 10;
            int b = rest % 10 / 5;
            ans = (ans + (int) ((long) (a + 1) * (a + b + 1) % MOD)) % MOD;
        }
        return ans;
    }
}

面试题 08.12. 八皇后

程序员面试金典(第 6 版)_第49张图片

class Solution {
    public List<List<String>> solveNQueens(int n) {
        int[] queens = new int[n];
        Arrays.fill(queens, -1);
        List<List<String>> solutions = new ArrayList<List<String>>();
        solve(solutions, queens, n, 0, 0, 0, 0);
        return solutions;
    }

    public void solve(List<List<String>> solutions, int[] queens, int n, int row, int columns, int diagonals1, int diagonals2) {
        if (row == n) {
            List<String> board = generateBoard(queens, n);
            solutions.add(board);
        } else {
            int availablePositions = ((1 << n) - 1) & (~(columns | diagonals1 | diagonals2));
            while (availablePositions != 0) {
                int position = availablePositions & (-availablePositions);
                availablePositions = availablePositions & (availablePositions - 1);
                int column = Integer.bitCount(position - 1);
                queens[row] = column;
                solve(solutions, queens, n, row + 1, columns | position, (diagonals1 | position) << 1, (diagonals2 | position) >> 1);
                queens[row] = -1;
            }
        }
    }

    public List<String> generateBoard(int[] queens, int n) {
        List<String> board = new ArrayList<String>();
        for (int i = 0; i < n; i++) {
            char[] row = new char[n];
            Arrays.fill(row, '.');
            row[queens[i]] = 'Q';
            board.add(new String(row));
        }
        return board;
    }
}

面试题 08.13. 堆箱子

程序员面试金典(第 6 版)_第50张图片

class Solution {
    public int pileBox(int[][] box) {
        Arrays.sort(box, (i, j) -> (i[0] != j[0] ? i[0] - j[0] : (i[1] != j[1] ? i[1] - j[1] : i[2] - j[2])));
        int[] dp = new int[box.length];
        for (int i = 0; i < dp.length; i++) {
            dp[i] = box[i][2];
            for (int j = 0; j < i; j++)
                if (box[i][0] > box[j][0] && box[i][1] > box[j][1] && box[i][2] > box[j][2])
                    dp[i] = Math.max(dp[i], box[i][2] + dp[j]);
        }
        return Arrays.stream(dp).max().orElse(0);
    }
}

面试题 10.01. 合并排序的数组

程序员面试金典(第 6 版)_第51张图片

class Solution {
    public void merge(int[] A, int m, int[] B, int n) {
        int k = n-- + m-- - 1;
        while (n >= 0 && m >= 0) {
            if (A[m] > B[n]) A[k--] = A[m--];
            else A[k--] = B[n--];
        }
        while (n >= 0) {
            A[k--] = B[n--];
        }
    }
}

面试题 10.02. 变位词组

程序员面试金典(第 6 版)_第52张图片

class Solution {
    static int[] nums = new int[]{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
            43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101}; //26个质数

    public List<List<String>> groupAnagrams(String[] ss) {
        List<List<String>> ans = new ArrayList<>();
        Map<Long, List<String>> map = new HashMap<>();
        for (String s : ss) {
            long cur = 1;//标识以提高map的查找效率
            // 若一个值和一个质数是一个单射关系,那么一组不同值的数组相乘结果就一定不相同
            for (char c : s.toCharArray()) cur *= nums[c - 'a'];// 质数唯一性定理
            List<String> list = map.getOrDefault(cur, new ArrayList<>());
            list.add(s);
            map.put(cur, list);
        }
        for (long key : map.keySet()) ans.add(map.get(key));
        return ans;
    }
}

面试题 10.03. 搜索旋转数组

在这里插入图片描述

class Solution {
    public int search(int[] arr, int target) {
        int n = arr.length;
        int result = -1;
        int l = 0, r = n - 1;
        while (l <= r) {
            int mid = (l + r + 1) >> 1;
            if (arr[l] == target) return l;
            else if (arr[l] == arr[mid]) l++;
            else if (arr[l] < arr[mid]) {
                if (arr[l] > target || arr[mid] < target) l = mid;
                else {
                    l = l + 1;
                    r = mid;
                }
            } else {
                if (arr[l] > target && arr[mid] < target) l = mid;
                else {
                    l = l + 1;
                    r = mid;
                }
            }
        }
        return result;
    }
}

面试题 10.05. 稀疏数组搜索

程序员面试金典(第 6 版)_第53张图片

class Solution {
    public int findString(String[] words, String s) {
        int left = 0, right = words.length - 1, m;
        while (left <= right) {
            m = (left + right) >> 1;
            while (m < right && "".equals(words[m])) m++;
            if (words[m].compareTo(s) > 0 || "".equals(words[m])) right = m - 1;
            else if (words[m].compareTo(s) < 0) left = m + 1;
            else return m;
        }
        return -1;
    }
}

面试题 10.09. 排序矩阵查找

程序员面试金典(第 6 版)_第54张图片

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int M = matrix.length;
        if (M == 0) return false;
        int N = matrix[0].length;
        if (N == 0) return false;
        int i = M - 1, j = 0;
        while (i >= 0 && j < N) {
            if (matrix[i][j] == target) return true;
            else if (matrix[i][j] > target) i--;
            else j++;
        }
        return false;
    }
}

面试题 10.11. 峰与谷

程序员面试金典(第 6 版)_第55张图片

class Solution {
    public void wiggleSort(int[] nums) {
        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 1; i += 2) {
            int temp = nums[i];
            nums[i] = nums[i + 1];
            nums[i + 1] = temp;
        }
    }
}

面试题 16.01. 交换数字

程序员面试金典(第 6 版)_第56张图片

class Solution {
    public int[] swapNumbers(int[] numbers) {
        numbers[0] = numbers[0] ^ numbers[1];
        numbers[1] = numbers[0] ^ numbers[1];
        numbers[0] = numbers[1] ^ numbers[0];
        return numbers;
    }
}

面试题 16.02. 单词频率

程序员面试金典(第 6 版)_第57张图片

class WordsFrequency {
    private Map<String, Integer> map = new HashMap<>();

    public WordsFrequency(String[] book) {
        for (String name : book) {
            map.put(name, map.getOrDefault(name, 0) + 1);
        }
    }

    public int get(String word) {
        return map.getOrDefault(word, 0);
    }
}

面试题 16.04. 井字游戏

程序员面试金典(第 6 版)_第58张图片

class Solution {
    public String tictactoe(String[] board) {
        int m = board.length;
        boolean hasBlank = false;
        int rowX, rowO, colX, colO;
        //行列检测
        for (int i = 0; i < m; i++) {
            rowX = 0;rowO = 0;colX = 0;colO = 0;
            for (int j = 0; j < m; j++) {
                if (board[i].charAt(j) == ' ') hasBlank = true;
                if (board[i].charAt(j) == 'X') rowX++;
                else if (board[i].charAt(j) == 'O') rowO++;
                if (board[j].charAt(i) == 'X') colX++;
                else if (board[j].charAt(i) == 'O') colO++;
            }
            if (rowX == m || colX == m) return "X";
            if (rowO == m || colO == m) return "O";
        }
        //对角线检测
        int leftTopX = 0, leftTopO = 0, leftBottomX = 0, leftBottomO = 0;
        for (int i = 0; i < m; i++) {
            if (board[i].charAt(i) == 'X') leftTopX++;
            else if (board[i].charAt(i) == 'O') leftTopO++;
            if (board[m - 1 - i].charAt(i) == 'X') leftBottomX++;
            else if (board[m - 1 - i].charAt(i) == 'O') leftBottomO++;
        }
        if (leftTopX == m || leftBottomX == m) return "X";
        if (leftTopO == m || leftBottomO == m) return "O";
        return hasBlank ? "Pending" : "Draw";
    }
}

面试题 16.05. 阶乘尾数

程序员面试金典(第 6 版)_第59张图片

class Solution {
    public int trailingZeroes(int n) {
        int res = 0;
        while (n > 0) {
            n /= 5;
            res += n;
        }
        return res;
    }
}

面试题 16.06. 最小差

程序员面试金典(第 6 版)_第60张图片

class Solution {
    public int smallestDifference(int[] a, int[] b) {
        int alen = a.length, blen = b.length;
        Arrays.sort(a);
        Arrays.sort(b);
        int minVal = Integer.MAX_VALUE, i = 0, j = 0;
        while (i < alen && j < blen) {
            long diff = a[i] - b[j];
            minVal = (int) Math.min(Math.abs(diff), minVal);
            if (diff < 0) i++;
            else j++;
        }
        return minVal;
    }
}

面试题 16.07. 最大数值

程序员面试金典(第 6 版)_第61张图片

class Solution {
    public int maximum(int a, int b) {
        int k = (int) (((long) a - (long) b) >>> 63 & 1);
        return a * (1 - k) + b * k;
    }
}

面试题 16.08. 整数的英语表示

程序员面试金典(第 6 版)_第62张图片

class Solution {
    String[] singles = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
    String[] teens = {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};
    String[] tens = {"", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};
    String[] thousands = {"", "Thousand", "Million", "Billion"};

    public String numberToWords(int num) {
        if (num == 0) {
            return "Zero";
        }
        StringBuffer sb = new StringBuffer();
        for (int i = 3, unit = 1000000000; i >= 0; i--, unit /= 1000) {
            int curNum = num / unit;
            if (curNum != 0) {
                num -= curNum * unit;
                sb.append(toEnglish(curNum)).append(thousands[i]).append(" ");
            }
        }
        return sb.toString().trim();
    }

    public String toEnglish(int num) {
        StringBuffer curr = new StringBuffer();
        int hundred = num / 100;
        num %= 100;
        if (hundred != 0) {
            curr.append(singles[hundred]).append(" Hundred ");
        }
        int ten = num / 10;
        if (ten >= 2) {
            curr.append(tens[ten]).append(" ");
            num %= 10;
        }
        if (num > 0 && num < 10) {
            curr.append(singles[num]).append(" ");
        } else if (num >= 10) {
            curr.append(teens[num - 10]).append(" ");
        }
        return curr.toString();
    }
}

面试题 16.10. 生存人数

程序员面试金典(第 6 版)_第63张图片

class Solution {
    public int maxAliveYear(int[] birth, int[] death) {
        // 先统计每年的人口数变化
        int[] change = new int[102];
        for (int i = 0; i < birth.length; i++) {
            // eg:1900年出生的人导致1900年变化人数加1,存储在change[0]
            change[birth[i] - 1900]++;
            // eg:1900年死亡的人导致1901年变化人数减1,存储在change[1]
            change[death[i] - 1899]--;
        }
        int maxAlive = 0;
        int curAlive = 0;
        int theYear = 1900;
        // 再根据每年变化人数求一个最大值
        for (int i = 0; i < 101; i++) {
            curAlive += change[i];
            if (curAlive > maxAlive) {
                maxAlive = curAlive;
                theYear = 1900 + i;
            }
        }
        return theYear;
    }
}

面试题 16.11. 跳水板

程序员面试金典(第 6 版)_第64张图片

class Solution {
    public int[] divingBoard(int shorter, int longer, int k) {
        if (k == 0) return new int[0];
        if (shorter == longer) return new int[]{shorter * k};
        int[] lengths = new int[k + 1];
        for (int i = 0; i <= k; i++) lengths[i] = shorter * (k - i) + longer * i;
        return lengths;
    }
}

面试题 16.14. 最佳直线

程序员面试金典(第 6 版)_第65张图片

class Solution {
    public int[] bestLine(int[][] points) {
        int n = points.length;
        Map<Double, Integer>[] dp = new Map[n];
        int maxCnt = 0, l = 0, r = 0;
        for (int i = n - 1; i >= 0; --i) {
            dp[i] = new HashMap<>();
            for (int j = n - 1; j > i; --j) {
                int dx = points[i][0] - points[j][0], dy = points[i][1] - points[j][1];
                double k = dx == 0 ? Double.POSITIVE_INFINITY : dy == 0 ? 0 : (double) dy / dx;
                int cnt = dp[j].getOrDefault(k, 1) + 1;
                dp[i].put(k, cnt);
                if (cnt >= maxCnt) {
                    maxCnt = cnt;
                    l = i;
                    r = j;
                }
            }
        }
        return new int[]{l, r};
    }
}

面试题 16.15. 珠玑妙算

程序员面试金典(第 6 版)_第66张图片

class Solution {
    public int[] masterMind(String solution, String guess) {
        int[][] hash = new int[26][2];
        int[] ans = new int[2];
        var s = solution.toCharArray();
        var g = guess.toCharArray();
        for (int i = 0; i < 4; i++) {
            if (s[i] == g[i]) {
                ans[0]++;
            } else {
                hash[s[i] - 'A'][0]++;
                hash[g[i] - 'A'][1]++;
            }
        }
        for (int[] arr : hash) { ans[1] += arr[0] > arr[1] ? arr[1] : arr[0];
        return ans;
    }
}

面试题 16.16. 部分排序

程序员面试金典(第 6 版)_第67张图片

class Solution {
    public int[] subSort(int[] array) {
        if (array == null || array.length < 1) return new int[]{-1, -1};
        // 从左往右找右端点
        int max = array[0], right = -1, n = array.length;
        for (int i = 1; i < n; i++) {
            if (array[i] >= max) max = array[i];
            else right = i;
        }
        if (right == -1) return new int[]{-1, -1};
        // 从右往左找左端点
        int min = array[n - 1], left = -1;
        for (int i = n - 1; i >= 0; i--) {
            if (array[i] <= min) min = array[i];
            else left = i;
        }
        return new int[]{left, right};
    }
}

面试题 16.17. 连续数列

程序员面试金典(第 6 版)_第68张图片

class Solution {
    public int maxSubArray(int[] nums) {
        int dp = 0, max = Integer.MIN_VALUE;
        for(int i = 0; i < nums.length; i++){
            dp = Math.max(nums[i], dp + nums[i]);
            max = Math.max(dp, max);
        }
        return max;
    }
}

面试题 16.19. 水域大小

程序员面试金典(第 6 版)_第69张图片

class Solution {
    int[][] grid_use;  // 标识当前为1的位置是否使用过
    int[] dx = {-1, 1, 0, 0, -1, -1, 1, 1};  // 某个坐标对应8个搜索位置(因为要求由垂直、水平或对角连接的水域为池塘)
    int[] dy = {0, 0, -1, 1, -1, 1, -1, 1};
    public int[] pondSizes(int[][] land) {
        grid_use = land;  // 若用过的坐标,即设置为1即可
        List<Integer> list = new ArrayList<>();  // 存储所有池塘面积
        for (int i = 0; i < land.length; i++){
            for (int j = 0; j < land[0].length; j++){
                // 遍历每个坐标点,若是水域0的坐标,
                // 则以当前水域(i,j)为起点继续向8个方向搜索联通的水域。
                if (land[i][j] == 0)
                    list.add(dfs(land, i, j));  // 水域面积放入list
            }
        }
        int[] res = new int[list.size()];  // list转换为对应数组,方便排序
        for (int i = 0; i < list.size(); i++) 
            res[i] = list.get(i);
        Arrays.sort(res);
        return res;  // 从小到大排序后的所有水域大小面积
    }

    public int dfs(int[][] land, int x, int y){
        int area = 1;  // 每个水域的最小面积都为1
        grid_use[x][y] = 1;  // 当前水域被使用过,则标记为1,防止再次被用
        for (int i = 0; i < 8; i++){  // 搜索上下左右、左上左下右上右下八个方向
            int a = x + dx[i];
            int b = y + dy[i];
            // 若当前水域未出界且未被搜索过,继续下一层搜索
            if (a >= 0 && a < land.length && b >= 0 && b < land[0].length && grid_use[a][b] == 0){
                area = area + dfs(land, a, b);  // 进入下一层也搜索,找到所有联通的水域面积
            }
        }
        return area;  // 返回连通水域面积
    }
}

面试题 16.20. T9键盘

程序员面试金典(第 6 版)_第70张图片

class Solution {
    public List<String> getValidT9Words(String num, String[] words) {
        List<String> res = new ArrayList<>();
        int length = num.length();
        int[] key = {2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6,
            7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9};
        boolean flag;
        for (String word: words) {
            flag = true;
            for (int i = 0; i < length; i++) {
                if (num.charAt(i) != key[word.charAt(i) - 'a'] + '0') {
                    flag = false;
                    break;
                }
            }
            if (flag) res.add(word);
        }
        return res;
    }
}

面试题 16.21. 交换和

程序员面试金典(第 6 版)_第71张图片

class Solution {
    public int[] findSwapValues(int[] array1, int[] array2) {
        int sum1 = 0, sum2 = 0;
        Set<Integer> container = new HashSet<>();
        for (int num : array1) sum1 += num;
        for (int num : array2) {
            container.add(num);
            sum2 += num;
        }
        int diff = sum1 - sum2;
        if (diff % 2 != 0) return new int[]{};
        diff /= 2;
        for (int num : array1) if (container.contains(num - diff)) return new int[]{num, num - diff};
        return new int[]{};
    }
}

面试题 16.22. 兰顿蚂蚁

程序员面试金典(第 6 版)_第72张图片

class Solution {
    private class Position {
        int x, y;
        public Position(int x, int y) {
            this.x = x;
            this.y = y;
        }
        @Override
        public boolean equals(Object obj) {
            if (obj == this) return true;
            if (!(obj instanceof Position)) return false;
            Position o = (Position) obj;
            return x == o.x && y == o.y;
        }
        @Override
        public int hashCode() {
            int result = x;
            result = 31 * result + y;
            return result;
        }
    }

    public List<String> printKMoves(int K) {
        char[] direction = {'L', 'U', 'R', 'D'};
        int[][] offset = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
        Position antPos = new Position(0, 0);
        int antDir = 2;
        Set<Position> blackSet = new HashSet<>();
        while (K > 0) {
            Position t = new Position(antPos.x, antPos.y);
            if (blackSet.add(t)) antDir = (antDir + 1) % 4;
            else {
                antDir = (antDir + 3) % 4;
                blackSet.remove(t);
            }
            antPos.x += offset[antDir][0];
            antPos.y += offset[antDir][1];
            K--;
        }
        int left = antPos.x, top = antPos.y, right = antPos.x, bottom = antPos.y;
        for (Position pos : blackSet) {
            left = Math.min(pos.x, left);
            top = Math.min(pos.y, top);
            right = Math.max(pos.x, right);
            bottom = Math.max(pos.y, bottom);
        }
        char[][] grid = new char[bottom - top + 1][right - left + 1];
        for (char[] row : grid)
            Arrays.fill(row, '_');
        for (Position pos : blackSet)
            grid[pos.y - top][pos.x - left] = 'X';
        grid[antPos.y - top][antPos.x - left] = direction[antDir];
        List<String> result = new ArrayList<>();
        for (char[] row : grid)
            result.add(String.valueOf(row));
        return result;
    }
}

面试题 16.24. 数对和

程序员面试金典(第 6 版)_第73张图片

class Solution {
    public List<List<Integer>> pairSums(int[] nums, int target) {
        Arrays.sort(nums);
        int start = 0, end = nums.length - 1;
        List<List<Integer>> ans = new ArrayList<>();
        while (start < end) {
            if (nums[start] + nums[end] == target) {
                List<Integer> list = new ArrayList<>();
                list.add(nums[start]);
                list.add(nums[end]);
                ans.add(list);
                start++;
                end--;
            } else if (nums[start] + nums[end] < target) start++;
            else end--;
        }
        return ans;
    }
}

面试题 16.25. LRU 缓存

程序员面试金典(第 6 版)_第74张图片

public class LRUCache {
    class DLinkedNode {
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;

        public DLinkedNode() {
        }

        public DLinkedNode(int _key, int _value) {
            key = _key;
            value = _value;
        }
    }

    private Map<Integer, DLinkedNode> cache = new HashMap<>();
    private int size;
    private int capacity;
    private DLinkedNode head, tail;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        // 使用伪头部和伪尾部节点
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if (node == null) return -1;
        moveToHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            DLinkedNode newNode = new DLinkedNode(key, value);
            cache.put(key, newNode);
            addToHead(newNode);
            ++size;
            if (size > capacity) {
                DLinkedNode tail = removeTail();
                cache.remove(tail.key);
                --size;
            }
        } else {
            node.value = value;
            moveToHead(node);
        }
    }

    private void addToHead(DLinkedNode node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void removeNode(DLinkedNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void moveToHead(DLinkedNode node) {
        removeNode(node);
        addToHead(node);
    }

    private DLinkedNode removeTail() {
        DLinkedNode res = tail.prev;
        removeNode(res);
        return res;
    }
}

面试题 16.26. 计算器

程序员面试金典(第 6 版)_第75张图片

class Solution {
    public int calculate(String s) {
        Deque<Integer> stack = new LinkedList<>();
        char opt = '+';
        int num = 0;
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (Character.isDigit(ch))num = num * 10 + (ch - '0');
            if ((!Character.isDigit(ch) && ch != ' ') || i == s.length() - 1) {
                if (opt == '+')stack.push(num);
                else if (opt == '-') stack.push(-num);
                else if (opt == '*')stack.push(stack.pop() * num);
                else stack.push(stack.pop() / num);
                num = 0;
                opt = ch;
            }
        }
        int res = 0;
        while (!stack.isEmpty())res += stack.pop();
        return res;
    }
}

面试题 17.04. 消失的数字

程序员面试金典(第 6 版)_第76张图片

class Solution {
    public int missingNumber(int[] nums) {
        int res = 0;
        for (int i = 0; i < nums.length; i++) {
            res ^= i;
            res ^= nums[i];
        }
        return res ^ nums.length;
    }
}

面试题 17.05. 字母与数字

程序员面试金典(第 6 版)_第77张图片

class Solution {
    public String[] findLongestSubarray(String[] array) {
        int len = array.length;
        int[] memo = new int[(len << 1) + 1];
        Arrays.fill(memo, -2);
        memo[len] = -1;
        int res = 0, count = 0, begin = 0, end = 0;
        for (int i = 0; i < len; ++i) {
            boolean is_num = true;
            for (char c : array[i].toCharArray())
                if (c < '0' || c > '9') {
                    is_num = false;
                    break;
                }
            count += is_num ? -1 : 1;
            //未曾见过该前缀和(即memo数组中没有记录)
            if (memo[count + len] <= -2) 
                memo[count + len] = i;  //记录该前缀和的下标
            //曾见过该前缀和(即memo数组中已有记录)
            else if (i - memo[count + len] > res) {
                begin = memo[count + len] + 1;
                end = i + 1;
                res = i - memo[count + len];
            }
        }
        return Arrays.copyOfRange(array, begin, end);
    }
}

面试题 17.06. 2出现的次数

程序员面试金典(第 6 版)_第78张图片

class Solution {
    public int numberOf2sInRange(int n) {
        if (n == 0) return 0;
        int digit = (int) Math.log10(n) + 1;
        int[][] dp = new int[digit + 1][2];
        dp[1][0] = n % 10 >= 2 ? 1 : 0;
        dp[1][1] = 1;
        for (int i = 2; i <= digit; i++) {
            int k = n / ((int) Math.pow(10, i - 1)) % 10;
            dp[i][0] = k * dp[i - 1][1] + dp[i - 1][0];
            if (k == 2) dp[i][0] += n % (int) Math.pow(10, i - 1) + 1;
            else if (k > 2) dp[i][0] += (int) Math.pow(10, i - 1)
            dp[i][1] = 10 * dp[i - 1][1] + (int) Math.pow(10, i - 1);
        }
        return dp[digit][0];
    }
}

面试题 17.08. 马戏团人塔

程序员面试金典(第 6 版)_第79张图片

class Solution {
    public int bestSeqAtIndex(int[] height, int[] weight) {
        int len = height.length, res = 0;
        int[][] person = new int[len][2];
        for (int i = 0; i < len; ++i) person[i] = new int[]{height[i], weight[i]};
        Arrays.sort(person, (a, b) -> a[0] == b[0] ? b[1] - a[1] : a[0] - b[0]);
        int[] dp = new int[len];
        for (int[] pair : person) {
            int i = Arrays.binarySearch(dp, 0, res, pair[1]);
            if (i < 0) i = -(i + 1);
            dp[i] = pair[1];
            if (i == res) ++res;
        }
        return res;
    }
}

面试题 17.09. 第 k 个数

程序员面试金典(第 6 版)_第80张图片

class Solution {
    public int getKthMagicNumber(int k) {
        int i3 = 0, i5 = 0, i7 = 0;
        int dp[] = new int[k];
        dp[0] = 1;
        for (int i = 1; i < k; i++) {
            dp[i] = Math.min(Math.min(3 * dp[i3], 5 * dp[i5]), 7 * dp[i7]);
            if (dp[i] == 3 * dp[i3]) i3++;
            if (dp[i] == 5 * dp[i5]) i5++;
            if (dp[i] == 7 * dp[i7]) i7++;
        }
        return dp[k - 1];
    }
}

面试题 17.10. 主要元素

程序员面试金典(第 6 版)_第81张图片

class Solution {
    public int majorityElement(int[] nums) {
        int n = nums.length;
        int x = -1, cnt = 0;
        for (int i : nums) {
            if (cnt == 0) {
                x = i;
                cnt = 1;
            } else cnt += x == i ? 1 : -1;
        }
        cnt = 0;
        for (int i : nums) if (x == i) cnt++;
        return cnt > n / 2 ? x : -1;
    }
}

面试题 17.11. 单词距离

程序员面试金典(第 6 版)_第82张图片

class Solution {
    public int findClosest(String[] words, String word1, String word2) {
        int start = Integer.MIN_VALUE / 2;
        int end = Integer.MAX_VALUE / 2;
        int ans = Integer.MAX_VALUE;
        for(int i=0; i<words.length; ++i){
            if(words[i].equals(word1)){
                start = i;
                ans = Math.min(ans, Math.abs(end-start));
            }
            if(words[i].equals(word2)){
                end = i;
                ans = Math.min(ans, Math.abs(end-start));
            }
        }
        return ans;
    }
}

面试题 17.12. BiNode

程序员面试金典(第 6 版)_第83张图片

class Solution {
    TreeNode head = null, pre = null;

    public TreeNode convertBiNode(TreeNode root) {
        if (root == null) return null;
        convertBiNode(root.left);
        if (head == null) head = root;
        else pre.right = root;
        pre = root;
        root.left = null;
        convertBiNode(root.right);
        return head;
    }
}

面试题 17.13. 恢复空格

程序员面试金典(第 6 版)_第84张图片

class Solution {
    public int respace(String[] dictionary, String sentence) {
        int m = sentence.length();
        int[] dp = new int[m + 1];
        for (int i = 1; i <= m; i++) {
            for (String word : dictionary) {
                int len = word.length();
                if (i >= len && word.equals(sentence.substring(i - len, i))) dp[i] = Math.max(dp[i], dp[i - len] + len);
                else dp[i] = Math.max(dp[i], dp[i - 1]);
            }
        }
        return m - dp[m];
    }
}

面试题 17.14. 最小K个数

程序员面试金典(第 6 版)_第85张图片

class Solution {
    int k;
    public int[] smallestK(int[] arr, int _k) {
        k = _k;
        int n = arr.length;
        int[] ans = new int[k];
        if (k == 0) return ans;
        qsort(arr, 0, n - 1);
        for (int i = 0; i < k; i++) ans[i] = arr[i];
        return ans;
    }
    void qsort(int[] arr, int l, int r) {
        if (l >= r) return ;
        int i = l, j = r;
        int ridx = new Random().nextInt(r - l + 1) + l;
        swap(arr, ridx, l);
        int x = arr[l];
        while (i < j) {
            while (i < j && arr[j] >= x) j--;
            while (i < j && arr[i] <= x) i++;
            swap(arr, i, j);
        }
        swap(arr, i, l);
        // 集中答疑:因为题解是使用「基准点左侧」来进行描述(不包含基准点的意思),所以这里用的 k(写成 k - 1 也可以滴
        if (i > k) qsort(arr, l, i - 1);
        if (i < k) qsort(arr, i + 1, r);
    }
    void swap(int[] arr, int l, int r) {
        int tmp = arr[l];
        arr[l] = arr[r];
        arr[r] = tmp;
    }
}

面试题 17.15. 最长单词

程序员面试金典(第 6 版)_第86张图片

class Solution {
    public String longestWord(String[] words) {
        Arrays.sort(words, Comparator
                .comparingInt(String::length).reversed()
                .thenComparing(Function.identity()));
        Set<String> set = new HashSet<>(Arrays.asList(words));
        for (String word : words) {
            set.remove(word);
            if (valid(set, word)) return word;
            set.add(word);
        }
        return "";
    }
    boolean valid(Set<String> set, String word) {
        for (int i = 1, n = word.length(); i < n; ++i) {
            String left = word.substring(0, i);
            if (!set.contains(left)) continue;// 必须包含左边
            String right = word.substring(i);
            if (set.contains(right)) return true;// 如果包含右边,则合法
            if (valid(set, right)) return true;// 不包含右边,递归检测右边
        }
        return false;
    }
}

面试题 17.16. 按摩师

程序员面试金典(第 6 版)_第87张图片

class Solution {
    public int massage(int[] nums) {
        int a = 0, b = 0;
        for (int i = 0; i < nums.length; i++) {
            int c = Math.max(b, a + nums[i]);
            a = b;
            b = c;
        }
        return b;
    }
}

面试题 17.18. 最短超串

程序员面试金典(第 6 版)_第88张图片

class Solution {
    public int[] shortestSeq(int[] big, int[] small) {
        int[] res = {};
        int smallLen = small.length, bigLen = big.length, left = 0, right = 0, minLen = bigLen;
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < smallLen; i++) map.putIfAbsent(small[i], 1);
        while (right < bigLen) {
            if (map.containsKey(big[right])) {
                if (map.get(big[right]) > 0) smallLen--;
                map.put(big[right], map.get(big[right]) - 1);
            }
            while (smallLen == 0) {
                if (right - left < minLen) {
                    minLen = right - left;
                    res = new int[]{left, right};
                }
                if (map.containsKey(big[left])) {
                    map.put(big[left], map.get(big[left]) + 1);
                    if (map.get(big[left]) > 0) {
                        smallLen++;
                    }
                }
                left++;
            }
            right++;
        }
        return res;
    }
}

面试题 17.19. 消失的两个数字

程序员面试金典(第 6 版)_第89张图片

class Solution {
    public int[] missingTwo(int[] nums) {
        int len = nums.length;
        int[] temp = new int[len + 2];
        int[] res = new int[2];
        for (int num : nums) temp[num - 1]--;
        int index = 0;
        for (int i = 0; i < temp.length; i++) {
            if (temp[i] == 0) res[index++] = i + 1;
        }
        return res;
    }
}

面试题 17.20. 连续中值

程序员面试金典(第 6 版)_第90张图片

class MedianFinder {
    PriorityQueue<Integer> left, right;
    boolean isLeft;

    public MedianFinder() {

        left = new PriorityQueue<>((x, y) -> y - x);
        right = new PriorityQueue<>();
    }
    
    public void addNum(int num) {
        
        left.offer(num);
        right.offer(left.poll());

        if (left.size() < right.size())
            left.offer(right.poll());
    }
    
    public double findMedian() {

        if (left.size() > right.size())
            return left.peek();
        
        return (left.peek() + right.peek()) / 2.0;
    }
}

面试题 17.21. 直方图的水量

程序员面试金典(第 6 版)_第91张图片

class Solution {
    public int trap(int[] height) {
        if (height==null||height.length<=2)return 0;
        int leftMax=height[0],rightMax=height[height.length-1];
        int left=0,right=height.length-2;
        int res=0;
        while (left<=right){
            if (leftMax<rightMax){
                if (height[left]<leftMax){
                    res+=leftMax-height[left];
                }else {
                    leftMax=height[left];
                }
                ++left;
            }else {
                if (height[right]<rightMax){
                    res+=rightMax-height[right];
                }else {
                    rightMax=height[right];
                }
                --right;
            }
        }
        return res;
    }
}

面试题 17.22. 单词转换

程序员面试金典(第 6 版)_第92张图片

class Solution {
    public List<String> findLadders(String beginWord, String endWord, List<String> wordList) {
        Queue<String> queue = new LinkedList<String>();
        List<String> ans = new LinkedList<String>();
        boolean[] visited = new boolean[wordList.size()];
        HashMap<String, String> map = new HashMap<>();
        if (!wordList.contains(endWord)) return ans;
        queue.add(beginWord);
        boolean flag = false;
        while (queue.size() != 0) {
            String queueHead = queue.poll();
            if (queueHead.equals(endWord)) {
                flag = true;
                break;
            }
            for (int i = 0; i < wordList.size(); i++) {
                if (!visited[i] && compare(wordList.get(i), queueHead)) {
                    queue.add(wordList.get(i));
                    visited[i] = true;
                    //存储前驱
                    map.put(wordList.get(i), queueHead);
                }
            }
        }
        if (!flag) return ans;
        String key = endWord;
        while (!map.get(key).equals(beginWord)) {
            ans.add(key);
            key = map.get(key);
        }
        ans.add(key);
        ans.add(map.get(key));
        Collections.reverse(ans);
        return ans;
    }

    public static boolean compare(String word1, String word2) {
        int diff = 0;
        for (int i = 0; i < word1.length(); i++) {
            if (word1.charAt(i) != word2.charAt(i)) {
                diff++;
                if (diff >= 2) {
                    return false;
                }
            }
        }
        return true;
    }
}

面试题 17.23. 最大黑方阵

程序员面试金典(第 6 版)_第93张图片

class Solution {
    private int global_row, global_col;
    private int[][] global_matrix;
    private int[] res = new int[3];

    public int[] findSquare(int[][] matrix) {
        global_matrix = matrix;
        if ((global_row = matrix.length) < 1) return new int[0];
        global_col = matrix[0].length;
        for (int i = 0; i < global_row - res[2]; ++i)
            and_operate(i);

        return res[2] > 0 ? res : new int[0];
    }

    private void and_operate(int cur_idx) {
        int[] first_row = global_matrix[cur_idx], base = first_row.clone();
        if (res[2] < 1)
            for (int i = 0; i < global_col; ++i)
                if (first_row[i] < 1) {
                    res[2] = 1;
                    res[0] = cur_idx;
                    res[1] = i;
                    break;
                }
        int offset = 0;
        for (int i = cur_idx + 1; i < global_row; ++i) {
            ++offset;
            int[] last_row = global_matrix[i];
            for (int j = 0; j < global_col; ++j)
                base[j] |= global_matrix[i][j];

            //存结果行中符合要求的区间的 左侧下标
            List<Integer> idx_list = new ArrayList<>();
            int count = 0, temp_idx = 0;
            for (; temp_idx < global_col - offset; ++temp_idx) {
                if (base[temp_idx] == 0) {
                    ++count;
                    if (base[temp_idx + offset] == 0)
                        idx_list.add(temp_idx);
                }
            }
            if (count < 2) {
                for (; temp_idx < global_col; ++temp_idx)
                    if (base[temp_idx] == 0 && ++count == 2)
                        break;
                //区间都无法构成(< 2个下标),直接return
                if (count < 2)
                    return;
            }
            //判断first_row和last_row是否在 结果行中0的下标所构成的区间内 有连续的0
            Loop:
            for (int begin_idx : idx_list) {
                int end_idx = begin_idx + offset;
                for (int l = begin_idx + 1; l < end_idx; ++l)
                    if (first_row[l] > 0 || last_row[l] > 0)
                        continue Loop;

                if (res[2] < offset + 1) {
                    res[2] = offset + 1;
                    res[0] = cur_idx;
                    res[1] = begin_idx;
                }
            }
        }
    }
}

面试题 17.24. 最大子矩阵

程序员面试金典(第 6 版)_第94张图片

class Solution {
    public int[] getMaxMatrix(int[][] matrix) {
        int[] ans = new int[4];
        int N = matrix.length, M = matrix[0].length;
        int[] b = new int[M];
        int sum = 0, maxsum = Integer.MIN_VALUE, bestr1 = 0, bestc1 = 0;
        for (int i = 0; i < N; i++) {
            for (int t = 0; t < M; t++) b[t] = 0;
            for (int j = i; j < N; j++) {
                sum = 0;
                for (int k = 0; k < M; k++) {
                    b[k] += matrix[j][k];
                    if (sum > 0) {
                        sum += b[k];
                    } else {
                        sum = b[k];
                        bestr1 = i;
                        bestc1 = k;
                    }
                    if (sum > maxsum) {
                        maxsum = sum;
                        ans[0] = bestr1;
                        ans[1] = bestc1;
                        ans[2] = j;
                        ans[3] = k;
                    }
                }
            }
        }
        return ans;
    }
}

面试题 17.26. 稀疏相似度

程序员面试金典(第 6 版)_第95张图片

class Solution {
    public List<String> computeSimilarities(int[][] docs) {
        HashMap<Integer, List<Integer>> map = new HashMap<>();
        int[][] help = new int[docs.length][docs.length];
        for (int i = 0; i < docs.length; i++) {
            for (int j : docs[i]) {
                List<Integer> list = map.get(j);
                if (list == null) {
                    list = new ArrayList<Integer>();
                    map.put(j, list);
                } else for (int k : list) help[i][k]++;
                list.add(i);
            }
        }
        List<String> retList = new ArrayList<>();
        for (int i = 0; i < docs.length; i++)
            for (int j = i; j < docs.length; j++)
                if (help[j][i] != 0)
                    retList.add(String.format("%d,%d: %.4f", i, j, 1.0 * help[j][i] / (docs[i].length + docs[j].length - help[j][i])));
        return retList;
    }
}

面试题19. 正则表达式匹配

程序员面试金典(第 6 版)_第96张图片

class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();

        boolean[][] f = new boolean[m + 1][n + 1];
        f[0][0] = true;
        for (int i = 0; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (p.charAt(j - 1) == '*') {
                    f[i][j] = f[i][j - 2];
                    if (matches(s, p, i, j - 1)) {
                        f[i][j] = f[i][j] || f[i - 1][j];
                    }
                } else {
                    if (matches(s, p, i, j)) {
                        f[i][j] = f[i - 1][j - 1];
                    }
                }
            }
        }
        return f[m][n];
    }

    public boolean matches(String s, String p, int i, int j) {
        if (i == 0) {
            return false;
        }
        if (p.charAt(j - 1) == '.') {
            return true;
        }
        return s.charAt(i - 1) == p.charAt(j - 1);
    }
}

面试题32 - I. 从上到下打印二叉树

程序员面试金典(第 6 版)_第97张图片

class Solution {
    public int[] levelOrder(TreeNode root) {
        if (root == null) return new int[0];
        Queue<TreeNode> queue = new LinkedList<>();
        List<Integer> list = new ArrayList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            list.add(node.val);
            if (node.left != null) queue.add(node.left);
            if (node.right != null) queue.add(node.right);
        }
        return list.stream().mapToInt(Integer::intValue).toArray();
    }
}

你可能感兴趣的:(算法,程序员面试金典,数据结构,leetcode,java)