二叉树算法训练

1.二叉树相关遍历 二叉搜索树(有序:根大于左子树小于右子树)相关遍历 (迭代和递归)

适当的练练手,记录一下。
System.out.println("中序遍历结果 = " + inorderTraversal(treeNode));
System.out.println("前序遍历结果 = " + inorderTraversal1(treeNode));
System.out.println("后序遍历结果 = " + inorderTraversal2(treeNode));
System.out.println("层序遍历结果 = " + levelOrder(treeNode));
System.out.println("二叉树的最大深度 = " + maxDepthInIteration(treeNode));
System.out.println("对称二叉树 = " + isSymmetric(treeNode));
System.out.println("二叉树路径总合 = " + hasPathSum(treeNode, 7));
System.out.println("从中序与后序遍历序列构造二叉树 中序显示= " + inorderTraversal(buildTree(inorder, postorder)));
System.out.println("二叉树的最近公共祖先 = " + lowestCommonAncestor(treeNode, new TreeNode(2),new TreeNode(3)));
System.out.println("二叉树的序列化与反序列化 = " + serialize(treeNode));
System.out.println("二叉树的反序列化 中序显示= " + inorderTraversal(deserialize("1,2,#,#,3,#,#,")));
System.out.println("是否是二叉搜索树 = " + isValidBST(treeNode));
System.out.println("searchBST 二叉树搜索树搜索某个节点= " + searchBST(treeNode,3));
System.out.println("二叉树搜索树插入某个节点 中序显示= " + inorderTraversal(insertIntoBST(treeNode,4)));

package com.test.algorithm;

import javafx.util.Pair;

import java.util.*;

/**
 * @author rs
 * @version 1.0
 * @date 2020/2/18 0018 10:33
 * 二叉树中序遍历 迭代
 *    1
 *  2  3 左右根
 */
public class OrderTraversalInBinaryTree {


    /*************************************************中序遍历**************************************************/
    /**
     * 中序遍历 迭代
     * @param root
     * @return
     */
    public static  List<Integer> inorderTraversal(TreeNode root) {

        List<Integer> list = new ArrayList<>();
        if(root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>(); // 栈先进后出
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()) { // 8.curr = null, statck.size = 1  12.cur != null 18.cur = null, stack.size = 0
            while(cur != null) {
                stack.push(cur); // 进栈 1.将整个cur推进stack里面 3.将左节点推进stack,此时stack.size = 2  13.将3,null,null推进栈
                cur = cur.left;  // 2.将cur的left赋值给cur,cur就成为了左节点 4.此时的cur的左节点为null   14.cur = null
            }
            cur = stack.pop(); // 出栈 5.因为先进后出,所以cur=root的左节点(这里需要有空间想象) 9.将之前的root弹出来  15.cur = 3
            list.add(cur.val); // 6.此时val = 2,因为在第4步整个cur的左节点都为null,如果它有右节点也是排在2后面的  10. 添加根节点1 16. 添加根节点3
            cur = cur.right; // 7.cur = null 11. cur = 3,null,null 17.cur = null
        }
        return list;
    }

    /**
     * 中序遍历 递归
     * @param root
     * @return
     */
    List<Integer> inorderTraversalForTterationList = new ArrayList<>();
    public List<Integer> inorderTraversalForTteration(TreeNode root) {

        if (root != null) {
            inorderTraversalForTteration(root.left);
            inorderTraversalForTterationList.add(root.val);
            inorderTraversalForTteration(root.right);
        }
        return inorderTraversalForTterationList;
    }

    /*************************************************前序遍历**************************************************/

    /**
     * 前序遍历 迭代 根左右
     * @param root
     * @return
     *
     */
    public static  List<Integer> inorderTraversal1(TreeNode root) {
        //
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()) {
            while(cur != null) {
                stack.push(cur);
                list.add(cur.val);
                cur = cur.left;
            }
            cur = stack.pop();
            cur = cur.right;
        }
        return list;
    }


    /**
     * 前序遍历 递归版
     * @param args
     */
    private List<Integer> ans = new ArrayList<>();

    public List<Integer> preorderTraversal(TreeNode root) {
        // 递归版
        if(root == null) return ans;
        ans.add(root.val);
        if(root.left != null) preorderTraversal(root.left);
        if(root.right != null) preorderTraversal(root.right);
        return ans;
    }
    /***********************************************后序遍历****************************************************/

    /**
     * 后序遍历 迭代 左右根
     * @param root
     * @return
     */
    public static  List<Integer> inorderTraversal2(TreeNode root) {
        //
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> s = new Stack<>();
        s.push(root);

        while( !s.isEmpty() ) {
            TreeNode node = s.pop(); // 1.出栈root
            if(node.left != null) {
                s.push(node.left); // 2.进栈 2,null,null
            }

            if(node.right != null) {
                s.push(node.right); // 3. 进栈 3,null,null
            }

            list.add(0, node.val); // 从最后插入依次插入 1 3 2 打印出来就是2 1 3
        }
        return list;
    }

    /**
     * 后序遍历 递归
     */
    List<Integer> postorderTraversalList = new LinkedList<>();
    public List<Integer> postorderTraversal(TreeNode root) {
        if(root == null)
            return ans;
        postorderTraversal(root.left);
        postorderTraversal(root.right);
        postorderTraversalList.add(root.val);
        return ans;
    }


     /***********************************************层序遍历*************************************************/
    /**
     *
     * @param root
     * @return
     */
     public static List<List<Integer>> levelOrder(TreeNode root) {
         List<List<Integer>> listList = new ArrayList<>();
         if(root == null) {
             return listList;
         }
         Queue<TreeNode> queue = new LinkedList<>();  // 练习了上面的题目,知道queue是先进先出就ok
         queue.add(root);
         while(!queue.isEmpty()) {
             int size = queue.size();
             List<Integer> list = new ArrayList<>();
             while(size > 0) {
                 TreeNode tempNode = queue.poll();
                 list.add(tempNode.val);
                 if(tempNode.left != null) {
                     queue.add(tempNode.left);
                 }
                 if(tempNode.right != null) {
                     queue.add(tempNode.right);
                 }
                 size--; // 从上到下,从左到右一个一个遍历
             }
             listList.add(list);
         }
         return listList;
     }

    /***********************************************练习1:二叉树的最大深度*************************************************/
    /**
     * 递归解法
     * @param root
     * @return
     */
    public static int maxDepth(TreeNode root) {
        if (root == null){
            return 0;
        } else {
            int left_depth = maxDepth(root.left);
            int right_depth = maxDepth(root.right);
            return Math.max(left_depth, right_depth) + 1;
        }
    }

    /**
     * 迭代解法
     * @param root
     * @return
     * 1.pair类似于map k,v结构
     * 2.不同点:stack.peek 不改变栈的值(不删除栈顶的值),pop会把栈顶的值删除。 相同点:大家都返回栈顶的值。
     * 总结:left进栈,加深度(出现右节点的左子节点), right:出栈
     */
    public static int maxDepthInIteration(TreeNode root) {
        int depth = 0;
        //1.初始化一个栈
        Stack<Pair<TreeNode, Integer>> stack = new Stack<>();
        TreeNode p = root;
        int current_depth = 0;
        while(p !=null || !stack.isEmpty()){
            if(p!=null){
                stack.push(new Pair(p,++ current_depth)); // 1. stack=k:1,2,3 v:1  4. stack=2,null,null 2  14.3,null,null 2
                depth = Math.max(depth,current_depth); // 2. d=1  5. d=2  15. d=2
                p = p.left; // 3.stack = 2,null,null  6.stack null,null,null size=2  16.null,null,null
            }else{
                current_depth = stack.isEmpty()? 0:stack.peek().getValue(); // 7. cd=2  10. cd=1  17.cd=2
                p = stack.pop().getKey(); // 8.stack 2,null,null  11. stack 1,2,3  18.3,null,null
                p = p.right; // 9. stack null,null,null  12. stack 3,null,nul  19. null,null,null 此时p=null,stack.isEmpty=true
            }
        }
        return depth;
    }

    /***********************************************练习2:对称二叉树*************************************************/

    /**
     * 迭代  对称是指对应数值相对,不仅是结构相对
     * @param root
     * @return
     */
    public static boolean isSymmetric(TreeNode root) {
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        q.add(root);
        while (!q.isEmpty()) {
            TreeNode t1 = q.poll();
            TreeNode t2 = q.poll();
            if (t1 == null && t2 == null) continue;
            if (t1 == null || t2 == null) return false;
            if (t1.val != t2.val) return false;
            // 顺序有讲究
            q.add(t1.left);
            q.add(t2.right);
            q.add(t1.right);
            q.add(t2.left);
        }
        return true;
    }

/*********************************************练习3:二叉树路径总合***************************************/
    /**
     * 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
     * @param root
     * @param sum
     * @return   递归解法
     * 思路:      1            1.num - 1,2.num -2,3.左null, 4.右走||判断,null 5.回到2,null,null,在回到1,2,3 6. 回到3,null,null
     *       2         3        7.走null,null,null两次,回到3,null,null 结束
     *   null null  null null
     */
    public static  boolean hasPathSum(TreeNode root, int sum) {
        if(root == null) {
            return false;
        }
        if(root.val == sum && root.left == null && root.right == null) {
            return true;
        }
        sum -= root.val;
        return hasPathSum(root.left, sum) || hasPathSum(root.right, sum);

    }


    /*****************************************总结练习1:从中序与后序遍历序列构造二叉树*********************************/
    /**
     * 例如,给出
     *
     * 中序遍历 inorder = [9,3,15,20,7]
     * 后序遍历 postorder = [9,15,7,20,3]
     * 返回如下的二叉树:
     *
     *     3
     *    / \
     *   9  20
     *     /  \
     *    15   7
     *    关键点:  1.两个数组的下标 0 和 len-1,先找后序的根,根据根来区分中序的左子树和右子树
     *            2.左节点递归(0~根-1,0~后序左+左子树-1)
     *            3.右节点递归(左子树+1~中序右边,后序左+左子树~后序右-1)
     *
     */
    private static int[] inorder = {15,9, 12, 3, 15, 20, 7 }; // 中序遍历 确定左右节点
    private static int[] postorder = { 15,12, 9, 15, 7, 20, 3 }; // 后序遍历 确定根节点
    public static TreeNode buildTree(int[] inorder, int[] postorder) {
        TreeNode root = create(inorder, postorder, 0, inorder.length - 1, 0, postorder.length - 1);
        return root;
    }
    private static TreeNode create(int[] inorder, int[] postorder, int inLeft, int inRight, int postLeft, int postRight) {
        if(postLeft > postRight){
            return null;   // 16. 退回到上一颗数15,null,null
        }
        TreeNode treeNode = new TreeNode(postorder[postRight]); // 1. 先找后序最后一个数,就是根节点   10.根节点为后序数组中的9 14.根是15
        int k = 0;
        for(int i = inLeft; i <= inRight; i++){ // 2.遍历一下中序数组
            if(inorder[i] == postorder[postRight]){ // 3.  如果数据里的值 = 根节点
                k = i;  // 4.根节点下标赋值给k = 3  11.根节点下标1   15. 0
                break;
            }
        }
        int numLeft = k - inLeft; // 5.(左子树的长度 = 3)在中序遍历中找到根节点,左边就是左子树,右边就是右子树  12. 1
        // 6. 左节点递归(0~根-1,0~后序左+左子树-1) 确定中序遍历的左子树的范围,0~2,  13. 0~1-1,0~0+1-1
        // 7.根据后序遍历特性:(左右根),根据第6步知道左子树的范围是0~2,所以在后序数组中的左子树范围也是0~2,并且知道下标2是根节点,值为9
        // 8.postLeft + numLeft - 1    19.回到9,null,null
        treeNode.left = create(inorder, postorder, inLeft, k - 1, postLeft, postLeft + numLeft - 1);
        // 17. 右节点递归(左子树+1~中序右边,后序左+左子树~后序右-1)此时左子树为15,null,null 它的左子树长度为0,所以要找左子树右节点:会return
        treeNode.right = create(inorder, postorder, k + 1, inRight, postLeft + numLeft, postRight - 1);  // 20 回到9,15,null 继续找左子树12这个根节点
        return treeNode; // 18.执行此步奏
    }

    /*****************************************总结练习2:二叉树的最近公共祖先*********************************/
    /**
     * 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
     *
     * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
     *
     * 示例 1:
     *       3
     *    5    1
     *  6  2  0  8
     *    7 4
     * 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
     * 输出: 3
     * 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
     * @param root
     * @param p
     * @param q
     * @return
     */
    public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //递归出口
        if (root == null || root == p || root == q) {
            return root;
        }
        //去该节点的左子树上找
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        //去该节点的右子树上找
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if (left == null) {
            //左子树上没有,说明在右子树上
            return right;
        } else if (right == null) {
            //右子树上没有,说明在左子树上
            return left;
        }
        //左右均有,说明该节点即为最近公共祖先
        return root;
    }


    /*****************************************总结练习3:二叉树的序列化与反序列化*********************************/
    /**
     * 二叉树的数的序列化和反序列化,二叉树实际是存储在内存中的,一旦断电或者是关机,二叉树的数据就会在内存中丢失。
     * 所以我们需要将二叉树的数据保存下来,这个过程叫做持久化或者序列化;将二叉树的数据保存到了磁盘之后,还需要将
     * 磁盘中的二叉树的数据加载到内存中去,这过程叫做反序列化。
     *
     * 解决思路:节点和节点之间使用,来分隔,空节点使用#来表示,为什么需要使用#来分隔?
     * 假如所有的节点都是相同的值,且不使用分隔符号,结构不同也会序列化为相同的结果
     */
    public static String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        encode(root, sb);
        return sb.toString();
    }

    private static void encode(TreeNode node, StringBuilder sb) {
        if (node == null) {
            sb.append("#,");
        } else {
            sb.append(node.val);
            sb.append(",");
            encode(node.left, sb);
            encode(node.right, sb);
        }
    }

    // Decodes your encoded data to tree.
    public static TreeNode deserialize(String data) {
        String[] vs = data.split(",");
        return decode(vs, new int[]{0});
    }

    private static TreeNode decode(String[] vs, int[] idx) {
        if (vs.length == 0 || idx[0] >= vs.length) {
            return null;
        }
        String s = vs[idx[0]];
        idx[0]++;
        if ("#".equals(s)) {
            return null;
        } else {
            int val = Integer.valueOf(s);
            TreeNode node = new TreeNode(val);
            node.left = decode(vs, idx);
            node.right = decode(vs, idx);
            return node;
        }
    }

    /*****************************************训练1:是否二叉树搜索树*********************************/
    /**
     * 二叉搜索树具有以下性质:每个节点中的值必须大于(或等于)其左侧子树中的任何值,但小于(或等于)其右侧子树中的任何值。
     * 关键点:只要有任何一颗树不满足条件,在递归下去或者递归回来时将结果层层return
     */
    static Integer pre = null;


    public static boolean isValidBST(TreeNode root) {
        return invailInorderTraversal(root);
    }

    private static boolean invailInorderTraversal(TreeNode root){
        if(root == null){
            return true;
        }
        if(!invailInorderTraversal(root.left)){
            return false;
        }
        if(pre != null && root.val <= pre){  // 走左子树 false时,根节点<= 左节点  走右子树false时:右根节点<=右根父节点
            return false;
        }
        pre = root.val;
        if(!invailInorderTraversal(root.right)){
            return false;
        }
        return true;
    }

    /*****************************************训练1:二叉树搜索树搜索某个节点*********************************/
    /**
     * 给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。
     * 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
     * @param root
     * @param val
     * @return
     */
    public static TreeNode searchBST(TreeNode root, int val) {

        if (root == null) {
            return null;
        }
        if (root.val == val) {
            return root;
        }
        else if (root.val > val) {
            return searchBST(root.left, val);
        }
        else {
            return searchBST(root.right, val);
        }
    }

    /*****************************************训练2:二叉树搜索树插入某个节点*********************************/
    public static TreeNode insertIntoBST(TreeNode root, int val) {
        if(root == null) {
            return new TreeNode(val);
        }
        // 大右小左
        if(root.val < val) {
            root.right = insertIntoBST(root.right, val);
        }else if(root.val > val) {
            root.left = insertIntoBST(root.left, val);
        }
        return root;
    }

     public static TreeNode insertIntoBST1(TreeNode root, int val) {
         if(root==null) return new TreeNode(val);
         TreeNode node = root;
         while(true)
         {
             if(node.val<val)
             {
                 if(node.right!=null) node = node.right;
                 else{
                     node.right = new TreeNode(val);
                     break;
                 }
             }
             else{
                 if(node.left!=null) node = node.left;
                 else{
                     node.left = new TreeNode(val);
                     break;
                 }
             }
         }
         return root;
     }


    /*****************************************训练3:二叉树搜索树删除某个节点*********************************/
    public static TreeNode deleteNode(TreeNode root, int key) {
        if (!containNode(root, key)) {
            return root;
        }
        if (root.val == key) {
            if (root.left == null) {
                return root.right;
            } else if (root.right == null) {
                return root.left;
            }
            TreeNode successor = findMin(root.right); // 找到右边最小的作为头节点
            successor.right = delMin(root.right); //删除掉这个最小节点,右边就遍历好了,在添加左边就行了
            successor.left = root.left;//
            return successor;
        } else if (root.val < key) {
            root.right = deleteNode(root.right, key);
            return root;
        } else {
            root.left = deleteNode(root.left, key);
            return root;
        }
    }

    private static boolean containNode(TreeNode treeNode, int key) {
        if (treeNode == null) {
            return false;
        }
        if (treeNode.val == key) {
            return true;
        } else if (treeNode.val > key) {
            return containNode(treeNode.left, key);
        } else {
            return containNode(treeNode.right, key);
        }
    }

    /*
     * return a treeNode whose key is the minimum in the tree
     */
    private static TreeNode findMin(TreeNode treeNode) {
        TreeNode cur = treeNode;
        while (cur != null) {
            if (cur.left == null) {
                return cur;
            }
            cur = cur.left;
        }
        return cur;
    }

    /*
     * return a treeNode after deleting its treeNode whose key is the minimum
     */
    private static TreeNode delMin(TreeNode treeNode) {
        if (treeNode.left == null) {
            return treeNode.right;
        }
        treeNode.left = delMin(treeNode.left);
        return treeNode;
    }


    /*****************************************进阶1:N叉树的前序遍历*********************************/
    /**
     *
     * @param root
     * @return
     */
    public static  List<Integer> preorder(Node root) {
        /*
        思路:前序遍历是根左右,先遍历根节点然后按顺序递归遍历孩子节点,当没有孩子节点时返回
         */
        List<Integer> res=new ArrayList<>();
        if (root==null)
        {
            return res;
        }
        preorder(root,res);
        return res;
    }

    private static void preorder(Node node,List<Integer> res)
    {
        res.add(node.val);
        List<Node> childList=node.children;
        if (childList.size()==0)
        {
            return;
        }else {
            for (int i = 0; i < childList.size(); i++) {
                preorder(childList.get(i),res);
            }
        }
    }




    /***********************************************main*************************************************/


    public static void main(String[] args) {
        TreeNode treeNode = new TreeNode(1);
        treeNode.left = new TreeNode(2);
        treeNode.right = new TreeNode(3);

        System.out.println("中序遍历结果 = " + inorderTraversal(treeNode));
        System.out.println("前序遍历结果 = " + inorderTraversal1(treeNode));
        System.out.println("后序遍历结果 = " + inorderTraversal2(treeNode));
        System.out.println("层序遍历结果 = " + levelOrder(treeNode));
        System.out.println("二叉树的最大深度 = " + maxDepthInIteration(treeNode));
        System.out.println("对称二叉树 = " + isSymmetric(treeNode));
        System.out.println("二叉树路径总合 = " + hasPathSum(treeNode, 7));
        System.out.println("从中序与后序遍历序列构造二叉树 中序显示= " + inorderTraversal(buildTree(inorder, postorder)));
        System.out.println("二叉树的最近公共祖先 = " + lowestCommonAncestor(treeNode, new TreeNode(2),new TreeNode(3)));
        System.out.println("二叉树的序列化与反序列化 = " + serialize(treeNode));
        System.out.println("二叉树的反序列化 中序显示= " + inorderTraversal(deserialize("1,2,#,#,3,#,#,")));
        System.out.println("是否是二叉搜索树 = " + isValidBST(treeNode));
        System.out.println("searchBST 二叉树搜索树搜索某个节点= " + searchBST(treeNode,3));
        System.out.println("二叉树搜索树插入某个节点  中序显示= " + inorderTraversal(insertIntoBST(treeNode,4)));
    }

}
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

class Node {
    int val;
    List<Node> children;

    Node(int x, List<Node> children) {
        val = x;
        children = children;
    }
}

欢迎关注我的微信公众号<搜索:汀雨笔记>,会首发一些最新文章哦!

下面是我的个人网站:http://ransongv587.com

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

推荐阅读更多精彩内容