二叉搜索树应用(补充)

1.不同的二叉搜索树(96-中)

题目描述:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例

输入:n = 3
输出:5

思路:注意二叉排序树,因此如果选择 i 为根节点,那么左子树共有 i - 1 个节点,右子树共有 n - i 个节点,每种根节点对应的二叉树的数量肯定是两个子树情况的乘积,一共有n个这样的根节点。

  • dp[i] 含义:i个节点组成的二叉搜索树数量
  • 状态转移方程:dp[i] += dp[j - 1] * dp[i - j]

事实上,状态转移方程在数学上被称为卡塔兰数,便于计算的定义如下:

  • C0 = 1, Cn+1 = 2*Cn*(2*n + 1)/(n + 2)

代码

public int numTrees(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 1;  // 空树也是一种二叉搜索树
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            dp[i] += dp[j - 1] * dp[i - j];
        }
    }
    return dp[n];
}

// 数学:卡特兰数
public int numTrees(int n) {
    long ans = 1;
    for (int i = 0; i < n; i++) {
        ans = ans * 2 * (2 * i + 1) / (i + 2);
    }
    return (int)ans;
}

2.不同的二叉搜索树II(95-中)

题目描述:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 ?返回满足题意的二叉搜索树。

示例

输入:n = 3
输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]

思路:二叉搜索树,对于任意一个节点大于左子树节点, 小于右子树节点。

  • 主要思想为分治递归树,然后左右子树列表构建结果树。
  • 注意:当n=0时,返回[], 但是F[0]]需要记录[[]]。

代码

public List<TreeNode> generateTrees(int n) {
    if (n < 1) {
        return new LinkedList<TreeNode>();
    }
    return generateSubTrees(1, n);
}
private List<TreeNode> generateSubTrees(int s, int e) {
    List<TreeNode> ret = new LinkedList<>();
    if (s > e) {
        //显然保证左子树或者右子树为空,正确构建树依赖下边左右子树列表的遍历,如果列表为空,那么循环不能进行。
        ret.add(null);
        return ret;
    }
    // 枚举所有可行的根节点
    for (int i = s; i <= e; ++i) {
        //1.分解:获取所有可行的左右子树集合
        List<TreeNode> leftSubTrees = generateSubTrees(s, i - 1);
        List<TreeNode> rightSubTrees = generateSubTrees(i + 1, e);
        //2.合并:合并左右子树,需要创建leftSubTrees.size() * rightSubTrees.size()个根节点
        for (TreeNode left : leftSubTrees) {
            for (TreeNode right : rightSubTrees) {
                TreeNode root = new TreeNode(i);
                root.left = left;
                root.right = right;
                ret.add(root);
            }
        }
    }
    return ret;
}

3.恢复二叉搜索树(99-难)

题目描述:给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。

进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?

示例

输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。

思路:显然利用中序序列的有序性,使用递归、迭代与morris(左子树为空和不为空两种情况)遍历解决,参考二叉树的中序遍历。注意交换的两种情况:

  • 相邻两个数字交换(一组逆序对)
  • 不相邻数字交换(两组逆序对)

代码

// 递归解法
TreeNode first = null, second = null, pre = null;
public void recoverTree(TreeNode root) {
    inOrder(root);
    int tmp = first.val;
    first.val = second.val;
    second.val = tmp;
}

public void inOrder(TreeNode root) {
    if (root == null) return;
    inOrder(root.left);
    if (pre != null && root.val < pre.val) {
        if (first == null) {
            first = pre;
            second = root;
        } else {
            second = root;
        }
    }
    pre = root;
    inOrder(root.right);
}
// 迭代解法
TreeNode first = null, second = null, pre = null;
public void recoverTree(TreeNode root) {
    inOrder(root);
    int tmp = first.val;
    first.val = second.val;
    second.val = tmp;
}

public void inOrder(TreeNode root) {
    if (root == null) return;
    Stack<TreeNode> stack = new Stack<>();
    while (root != null || !stack.isEmpty()) {
        while (root != null) {
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        if (pre != null && root.val < pre.val) {
            if (first == null) {
                first = pre;
                second = root;
            } else {
                second = root;
            }
        }
        pre = root;
        root = root.right;
    }
}
// morris解法
public void recoverTree(TreeNode root) {
    TreeNode first = null;
    TreeNode second = null;
    TreeNode cur = root;
    TreeNode pre_new = null;
    while (cur != null) {
        // 情况 1
        if (cur.left == null) {
            /*******************************************************/
            if (pre_new != null && cur.val < pre_new.val) {
                if (first == null) {
                    first = pre_new;
                    second = cur;
                } else {
                    second = cur;
                }
            }
            pre_new = cur;
            /*******************************************************/
            cur = cur.right;
        } else {
            // 找左子树最右边的节点
            TreeNode pre = cur.left;
            while (pre.right != null && pre.right != cur) {
                pre = pre.right;
            }
            // 情况 2.1(第一次到达左子树的最右节点,改变指针)
            if (pre.right == null) {
                pre.right = cur;
                cur = cur.left;
            }
            // 情况 2.2(第二到达,恢复指针)
            if (pre.right == cur) {
                pre.right = null; // 这里可以恢复为 null
                /*******************************************************/
                if (pre_new != null && cur.val < pre_new.val) {
                    if (first == null) {
                        first = pre_new;
                        second = cur;
                    } else {
                        second = cur;
                    }
                }
                pre_new = cur;
                /*******************************************************/
                cur = cur.right;
            }
        }
    }
    
    int temp = first.val;
    first.val = second.val;
    second.val = temp;
}

4.验证二叉搜索树(98-中)

题目描述:验证一棵树是否为二叉搜索树:左子树节点都小于当前节点,右子树节点都大于当前节点,左右子树本身也是二叉搜索树。

示例

输入:
    5
   / \
  1   4
     / \
    3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
     根节点的值为 5 ,但是其右子节点值为 4 。

思路:可以使用额外空间,可以通过二叉搜索树中序遍历的有序性进行判断,实现简单。

这里使用递归进行判断:

  • 终止条件:root == null return true(空树也是二叉搜索树)
  • 递归逻辑:当前节点与上一个节点值的大小关系
  • 与二叉树的中序遍历相同:先左子树,当前节点,右子树

代码

List<Integer> res = new ArrayList<>();
public boolean isValidBST(TreeNode root) {
    inOrder(root);
    for (int i = 1; i < res.size(); i++) {
        if (res.get(i) <= res.get(i - 1)) {
            return false;
        }
    }
    return true;
}
private void inOrder(TreeNode root) {
    if (root == null) return;
    inOrder(root.left);
    res.add(root.val);
    inOrder(root.right);
}

//设置一个pre变量存上一个节点的值
long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
   if (root == null) return true;
   if (!isValidBST(root.left)) {
       return false;
   }
   //访问当前节点,当前节点小于或者等于中序遍历的上一个节点,不满足,否则继续
   if (root.val <= pre) {
       return false;
   }
   pre = root.val;
   return isValidBST(root.right);
}

7.不同的二叉搜索树(96-中)

题目描述:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例

输入:n = 3
输出:5

思路:注意二叉排序树,因此如果选择 i 为根节点,那么左子树共有 i - 1 个节点,右子树共有 n - i 个节点,每种根节点对应的二叉树的数量肯定是两个子树情况的乘积,一共有n个这样的根节点。

  • dp[i] 含义:i个节点组成的二叉搜索树数量
  • 状态转移方程:dp[i] += dp[j - 1] * dp[i - j]

事实上,状态转移方程在数学上被称为卡塔兰数,便于计算的定义如下:

  • C0 = 1, Cn+1 = 2*Cn*(2*n + 1)/(n + 2)

代码

public int numTrees(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 1;  // 空树也是一种二叉搜索树
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            dp[i] += dp[j - 1] * dp[i - j];
        }
    }
    return dp[n];
}

// 数学:卡特兰数
public int numTrees(int n) {
    long ans = 1;
    for (int i = 0; i < n; i++) {
        ans = ans * 2 * (2 * i + 1) / (i + 2);
    }
    return (int)ans;
}

8.不同的二叉搜索树II(95-中)

题目描述:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 ?返回满足题意的二叉搜索树。

示例

输入:n = 3
输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]

思路:二叉搜索树,对于任意一个节点大于左子树节点, 小于右子树节点。

  • 主要思想为分治递归树,然后左右子树列表构建结果树。
  • 注意:当n=0时,返回[], 但是F[0]]需要记录[[]]。

代码

public List<TreeNode> generateTrees(int n) {
    if (n < 1) {
        return new LinkedList<TreeNode>();
    }
    return generateSubTrees(1, n);
}
private List<TreeNode> generateSubTrees(int s, int e) {
    List<TreeNode> ret = new LinkedList<>();
    if (s > e) {
        //显然保证左子树或者右子树为空,正确构建树依赖下边左右子树列表的遍历,如果列表为空,那么循环不能进行。
        ret.add(null);
        return ret;
    }
    // 枚举所有可行的根节点
    for (int i = s; i <= e; ++i) {
        //1.分解:获取所有可行的左右子树集合
        List<TreeNode> leftSubTrees = generateSubTrees(s, i - 1);
        List<TreeNode> rightSubTrees = generateSubTrees(i + 1, e);
        //2.合并:合并左右子树,需要创建leftSubTrees.size() * rightSubTrees.size()个根节点
        for (TreeNode left : leftSubTrees) {
            for (TreeNode right : rightSubTrees) {
                TreeNode root = new TreeNode(i);
                root.left = left;
                root.right = right;
                ret.add(root);
            }
        }
    }
    return ret;
}

8.恢复二叉搜索树(99-难)

题目描述:给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。

进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?

示例

输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。

思路:显然利用中序序列的有序性,使用递归、迭代与morris(左子树为空和不为空两种情况)遍历解决,参考二叉树的中序遍历。注意交换的两种情况:

  • 相邻两个数字交换(一组逆序对)
  • 不相邻数字交换(两组逆序对)

代码

// 递归解法
TreeNode first = null, second = null, pre = null;
public void recoverTree(TreeNode root) {
    inOrder(root);
    int tmp = first.val;
    first.val = second.val;
    second.val = tmp;
}

public void inOrder(TreeNode root) {
    if (root == null) return;
    inOrder(root.left);
    if (pre != null && root.val < pre.val) {
        if (first == null) {
            first = pre;
            second = root;
        } else {
            second = root;
        }
    }
    pre = root;
    inOrder(root.right);
}
// 迭代解法
TreeNode first = null, second = null, pre = null;
public void recoverTree(TreeNode root) {
    inOrder(root);
    int tmp = first.val;
    first.val = second.val;
    second.val = tmp;
}

public void inOrder(TreeNode root) {
    if (root == null) return;
    Stack<TreeNode> stack = new Stack<>();
    while (root != null || !stack.isEmpty()) {
        while (root != null) {
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        if (pre != null && root.val < pre.val) {
            if (first == null) {
                first = pre;
                second = root;
            } else {
                second = root;
            }
        }
        pre = root;
        root = root.right;
    }
}
// morris解法
public void recoverTree(TreeNode root) {
    TreeNode first = null;
    TreeNode second = null;
    TreeNode cur = root;
    TreeNode pre_new = null;
    while (cur != null) {
        // 情况 1
        if (cur.left == null) {
            /*******************************************************/
            if (pre_new != null && cur.val < pre_new.val) {
                if (first == null) {
                    first = pre_new;
                    second = cur;
                } else {
                    second = cur;
                }
            }
            pre_new = cur;
            /*******************************************************/
            cur = cur.right;
        } else {
            // 找左子树最右边的节点
            TreeNode pre = cur.left;
            while (pre.right != null && pre.right != cur) {
                pre = pre.right;
            }
            // 情况 2.1(第一次到达左子树的最右节点,改变指针)
            if (pre.right == null) {
                pre.right = cur;
                cur = cur.left;
            }
            // 情况 2.2(第二到达,恢复指针)
            if (pre.right == cur) {
                pre.right = null; // 这里可以恢复为 null
                /*******************************************************/
                if (pre_new != null && cur.val < pre_new.val) {
                    if (first == null) {
                        first = pre_new;
                        second = cur;
                    } else {
                        second = cur;
                    }
                }
                pre_new = cur;
                /*******************************************************/
                cur = cur.right;
            }
        }
    }
    
    int temp = first.val;
    first.val = second.val;
    second.val = temp;
}

8.验证二叉搜索树(98-中)

题目描述:验证一棵树是否为二叉搜索树:左子树节点都小于当前节点,右子树节点都大于当前节点,左右子树本身也是二叉搜索树。

示例

输入:
    5
   / \
  1   4
     / \
    3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
     根节点的值为 5 ,但是其右子节点值为 4 。

思路:可以使用额外空间,可以通过二叉搜索树中序遍历的有序性进行判断,实现简单。

这里使用递归进行判断:

  • 终止条件:root == null return true(空树也是二叉搜索树)
  • 递归逻辑:当前节点与上一个节点值的大小关系
  • 与二叉树的中序遍历相同:先左子树,当前节点,右子树

代码

List<Integer> res = new ArrayList<>();
public boolean isValidBST(TreeNode root) {
    inOrder(root);
    for (int i = 1; i < res.size(); i++) {
        if (res.get(i) <= res.get(i - 1)) {
            return false;
        }
    }
    return true;
}
private void inOrder(TreeNode root) {
    if (root == null) return;
    inOrder(root.left);
    res.add(root.val);
    inOrder(root.right);
}

//设置一个pre变量存上一个节点的值
long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
   if (root == null) return true;
   if (!isValidBST(root.left)) {
       return false;
   }
   //访问当前节点,当前节点小于或者等于中序遍历的上一个节点,不满足,否则继续
   if (root.val <= pre) {
       return false;
   }
   pre = root.val;
   return isValidBST(root.right);
}

7.不同的二叉搜索树(96-中)

题目描述:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例

输入:n = 3
输出:5

思路:注意二叉排序树,因此如果选择 i 为根节点,那么左子树共有 i - 1 个节点,右子树共有 n - i 个节点,每种根节点对应的二叉树的数量肯定是两个子树情况的乘积,一共有n个这样的根节点。

  • dp[i] 含义:i个节点组成的二叉搜索树数量
  • 状态转移方程:dp[i] += dp[j - 1] * dp[i - j]

事实上,状态转移方程在数学上被称为卡塔兰数,便于计算的定义如下:

  • C0 = 1, Cn+1 = 2*Cn*(2*n + 1)/(n + 2)

代码

public int numTrees(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 1;  // 空树也是一种二叉搜索树
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            dp[i] += dp[j - 1] * dp[i - j];
        }
    }
    return dp[n];
}

// 数学:卡特兰数
public int numTrees(int n) {
    long ans = 1;
    for (int i = 0; i < n; i++) {
        ans = ans * 2 * (2 * i + 1) / (i + 2);
    }
    return (int)ans;
}

8.不同的二叉搜索树II(95-中)

题目描述:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 ?返回满足题意的二叉搜索树。

示例

输入:n = 3
输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]

思路:二叉搜索树,对于任意一个节点大于左子树节点, 小于右子树节点。

  • 主要思想为分治递归树,然后左右子树列表构建结果树。
  • 注意:当n=0时,返回[], 但是F[0]]需要记录[[]]。

代码

public List<TreeNode> generateTrees(int n) {
    if (n < 1) {
        return new LinkedList<TreeNode>();
    }
    return generateSubTrees(1, n);
}
private List<TreeNode> generateSubTrees(int s, int e) {
    List<TreeNode> ret = new LinkedList<>();
    if (s > e) {
        //显然保证左子树或者右子树为空,正确构建树依赖下边左右子树列表的遍历,如果列表为空,那么循环不能进行。
        ret.add(null);
        return ret;
    }
    // 枚举所有可行的根节点
    for (int i = s; i <= e; ++i) {
        //1.分解:获取所有可行的左右子树集合
        List<TreeNode> leftSubTrees = generateSubTrees(s, i - 1);
        List<TreeNode> rightSubTrees = generateSubTrees(i + 1, e);
        //2.合并:合并左右子树,需要创建leftSubTrees.size() * rightSubTrees.size()个根节点
        for (TreeNode left : leftSubTrees) {
            for (TreeNode right : rightSubTrees) {
                TreeNode root = new TreeNode(i);
                root.left = left;
                root.right = right;
                ret.add(root);
            }
        }
    }
    return ret;
}

8.恢复二叉搜索树(99-难)

题目描述:给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。

进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?

示例

输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。

思路:显然利用中序序列的有序性,使用递归、迭代与morris(左子树为空和不为空两种情况)遍历解决,参考二叉树的中序遍历。注意交换的两种情况:

  • 相邻两个数字交换(一组逆序对)
  • 不相邻数字交换(两组逆序对)

代码

// 递归解法
TreeNode first = null, second = null, pre = null;
public void recoverTree(TreeNode root) {
    inOrder(root);
    int tmp = first.val;
    first.val = second.val;
    second.val = tmp;
}

public void inOrder(TreeNode root) {
    if (root == null) return;
    inOrder(root.left);
    if (pre != null && root.val < pre.val) {
        if (first == null) {
            first = pre;
            second = root;
        } else {
            second = root;
        }
    }
    pre = root;
    inOrder(root.right);
}
// 迭代解法
TreeNode first = null, second = null, pre = null;
public void recoverTree(TreeNode root) {
    inOrder(root);
    int tmp = first.val;
    first.val = second.val;
    second.val = tmp;
}

public void inOrder(TreeNode root) {
    if (root == null) return;
    Stack<TreeNode> stack = new Stack<>();
    while (root != null || !stack.isEmpty()) {
        while (root != null) {
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        if (pre != null && root.val < pre.val) {
            if (first == null) {
                first = pre;
                second = root;
            } else {
                second = root;
            }
        }
        pre = root;
        root = root.right;
    }
}
// morris解法
public void recoverTree(TreeNode root) {
    TreeNode first = null;
    TreeNode second = null;
    TreeNode cur = root;
    TreeNode pre_new = null;
    while (cur != null) {
        // 情况 1
        if (cur.left == null) {
            /*******************************************************/
            if (pre_new != null && cur.val < pre_new.val) {
                if (first == null) {
                    first = pre_new;
                    second = cur;
                } else {
                    second = cur;
                }
            }
            pre_new = cur;
            /*******************************************************/
            cur = cur.right;
        } else {
            // 找左子树最右边的节点
            TreeNode pre = cur.left;
            while (pre.right != null && pre.right != cur) {
                pre = pre.right;
            }
            // 情况 2.1(第一次到达左子树的最右节点,改变指针)
            if (pre.right == null) {
                pre.right = cur;
                cur = cur.left;
            }
            // 情况 2.2(第二到达,恢复指针)
            if (pre.right == cur) {
                pre.right = null; // 这里可以恢复为 null
                /*******************************************************/
                if (pre_new != null && cur.val < pre_new.val) {
                    if (first == null) {
                        first = pre_new;
                        second = cur;
                    } else {
                        second = cur;
                    }
                }
                pre_new = cur;
                /*******************************************************/
                cur = cur.right;
            }
        }
    }
    
    int temp = first.val;
    first.val = second.val;
    second.val = temp;
}

8.验证二叉搜索树(98-中)

题目描述:验证一棵树是否为二叉搜索树:左子树节点都小于当前节点,右子树节点都大于当前节点,左右子树本身也是二叉搜索树。

示例

输入:
    5
   / \
  1   4
     / \
    3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
     根节点的值为 5 ,但是其右子节点值为 4 。

思路:可以使用额外空间,可以通过二叉搜索树中序遍历的有序性进行判断,实现简单。

这里使用递归进行判断:

  • 终止条件:root == null return true(空树也是二叉搜索树)
  • 递归逻辑:当前节点与上一个节点值的大小关系
  • 与二叉树的中序遍历相同:先左子树,当前节点,右子树

代码

List<Integer> res = new ArrayList<>();
public boolean isValidBST(TreeNode root) {
    inOrder(root);
    for (int i = 1; i < res.size(); i++) {
        if (res.get(i) <= res.get(i - 1)) {
            return false;
        }
    }
    return true;
}
private void inOrder(TreeNode root) {
    if (root == null) return;
    inOrder(root.left);
    res.add(root.val);
    inOrder(root.right);
}

//设置一个pre变量存上一个节点的值
long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
   if (root == null) return true;
   if (!isValidBST(root.left)) {
       return false;
   }
   //访问当前节点,当前节点小于或者等于中序遍历的上一个节点,不满足,否则继续
   if (root.val <= pre) {
       return false;
   }
   pre = root.val;
   return isValidBST(root.right);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容