Leetcode刷题常用模板总结

73 阅读2分钟

递归大致思路

  1. 确定递归函数的参数和返回值
  2. 确定终止条件
  3. 确定单层递归的逻辑

先序 递归遍历

中序 递归遍历

后序 递归遍历

先序 迭代遍历

class Solution {
    List<Integer> ans = new ArrayList<Integer>();
    public List<Integer> preorderTraversal(TreeNode root) {
        preOrder(root);
        return ans;
    }

    public void preOrder(TreeNode node){
        if (node == null) return ;
        ans.add(node.val);
        preOrder(node.left);
        preOrder(node.right);
    }
}

中序 迭代遍历

class Solution {
    List<Integer> ans = new ArrayList<Integer>();
    public List<Integer> preorderTraversal(TreeNode root) {
        preOrder(root);
        return ans;
    }

    public void preOrder(TreeNode node){
        if (node == null) return ;
        preOrder(node.left);
        ans.add(node.val);
        preOrder(node.right);
    }
}

后序 迭代遍历

class Solution {
    List<Integer> ans = new ArrayList<Integer>();
    public List<Integer> preorderTraversal(TreeNode root) {
        preOrder(root);
        return ans;
    }

    public void preOrder(TreeNode node){
        if (node == null) return ;
        preOrder(node.left);
        preOrder(node.right);
        ans.add(node.val);
    }
}

层序遍历

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if (root == null)
            return new ArrayList<>();
        List<List<Integer>> res = new ArrayList<>();
        // 使用队列来完成层序遍历
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);
        while(!queue.isEmpty()){
            int num = queue.size();
            List<Integer> list = new ArrayList<>();
            while(num>0){
                // 出队列,将它下一层的子树添加到队列中
                TreeNode node = queue.poll();
                list.add(node.val);
                if(node.left!=null)
                    queue.add(node.left);
                if(node.right!=null)
                    queue.add(node.right);
                // 通过这个计数来区别不同层节点
                num--;
            }
            // 遍历完二叉树的一层,将结果添加到结果集
            res.add(list);
        }
        return res;
    }
}

回溯算法

// 可以在主函数之外,作为类的全局变量
void backtrace(全局){
    if(终止条件){
      // 收集结果
      return;
    }
    for(集合元素){
      // 处理节点
      // 递归函数
      // 撤销操作
    }
    return;
}

什么时候使用 used 数组,什么时候使用 begin 变量

  • 排列问题,讲究顺序(即 [2, 2, 3] 与 [2, 3, 2] 视为不同列表时),需要记录哪些数字已经使用过,此时用 used 数组;
  • 组合问题,不讲究顺序(即 [2, 2, 3] 与 [2, 3, 2] 视为相同列表时),需要按照某种顺序搜索,此时使用 begin 变量。

动态规划

  1. 确定dp数组下标的意义
  2. 确定递推关系
  3. 确定数组初始状态
  4. 确定递推顺序
  5. 举例推导dp数组

以下是使用二维dp数组解决不同路径的代码

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n]; 
        for (int i=0;i<m;i++){
            dp[i][0] = 1;
        }
        for (int i=0;i<n;i++){
            dp[0][i] = 1;
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                dp[i][j] = dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}

优化存储的动态规划

层序遍历

层序遍历