03 找出重复数字

  1. public int findRepeatNumber(int[] nums) {
  2. int temp;
  3. for(int i=0;i<nums.length;i++){
  4. while (nums[i]!=i){
  5. if(nums[i]==nums[nums[i]]){
  6. return nums[i];
  7. }
  8. temp=nums[i];
  9. nums[i]=nums[temp];
  10. nums[temp]=temp;
  11. }
  12. }
  13. return -1;
  14. }

原地置换,时间O(n),空间O(1);


04 (有序)二维数组查找

  1. public boolean findNumberIn2DArray(int[][] matrix, int target) {
  2. int i = matrix.length - 1, j = 0;
  3. while(i >= 0 && j < matrix[0].length)
  4. {
  5. if(matrix[i][j] > target) i--;
  6. else if(matrix[i][j] < target) j++;
  7. else return true;
  8. }
  9. return false;
  10. }

按边查找


07 重建二叉树

给出前序中序,重建二叉树。
三种方法:

  1. 递归,
    • 找到根节点后,再分别构建左右子树。
  2. 迭代,
    • 使用前序遍历一直构造左子树,通过与中序比对找到对应右节点位置。
  3. 索引,
    • 让前序遍历的序列有中序序列的索引,再遍历前序时按照二叉排序树的方式插入。(左节点比根节点索引小,右节点比根节点索引大)
    • 此方法学自Q-WHai大佬的重建二叉树三种方法

递归:

class Solution {
    private Map<Integer,Integer> indexMap; 

    private TreeNode reBuildTree(int[] pre,int preStart,int preEnd,int[] in,int inStart,int inEnd) {
        if(preStart>preEnd || inStart>inEnd) { 
            return null;
        }
        int pre_root = preStart;
        int in_root = indexMap.get(pre[pre_root]);
        TreeNode cur_root = new TreeNode(pre[pre_root]); //构建当前树的根节点
        cur_root.left = reBuildTree(pre,preStart+1,preStart+in_root-inStart,in,inStart,in_root-1);
        cur_root.right = reBuildTree(pre,preStart+in_root-inStart+1,preEnd,in,in_root+1,inEnd);
        return cur_root;
    }

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        indexMap = new HashMap<>(); //方便查找中序遍历中的节点位置
        for (int i = 0; i < preorder.length; i++) {
            indexMap.put(inorder[i], i);
        }
        TreeNode root = reBuildTree(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
        return root;
    }
}

09 用两个栈实现队列

stack1 用于实现队尾插入,stack2 用于实现队头弹出
小技巧是不必每次都将stack1倒入stack2。

class CQueue {
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;

    public CQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }

    public void appendTail(int value) {
        stack1.push(value);
    }

    public int deleteHead() {
        if(stack2.isEmpty()) {
            while (!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
        }
        if(stack2.isEmpty()) {
            return - 1;
        } else {
            return stack2.pop();
        }
    }
}

11 旋转数组的最小数字

二分查找不只在有序数组中能使用,二分减治思想是分治的特殊情况,只要划分出一个有序的查找区间,就能使用二分法。

class Solution {
    public int minArray(int[] numbers) {
        int n = numbers.length;
        int left = 0;
        int right = n-1;
        while (left < right) {
            int mid = (left + right) / 2;
            if(numbers[mid] < numbers[right]) {
                right = mid;
            } else if(numbers[mid] > numbers[right]) {
                left = mid+1;
            } else {  //相等的时候丢弃最右边的
                right -= 1;
            }
        }
        return numbers[left];
    }
}

12 矩阵中的路径

中规中矩的DFS

class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words = word.toCharArray();
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                if(dfs(board, words, i, j, 0)) return true;
            }
        }
        return false;
    }
    private boolean dfs(char[][] board, char[] word, int i, int j, int k) {
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
        if(k == word.length - 1) return true;
        board[i][j] = '\0'; //标记为空,防止重复搜索
        boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) ||
                dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
        board[i][j] = word[k];
        return res;
    }
}