leetcode科学刷题(1)-二叉树(数据结构篇)

网上冲浪的时候,偶然看到科学刷leetcode算法题的方法--算法模版,实践是检验真理的唯一标准,我决定按照他的方法试一试,他这个上面是go语言实现的,我用Java跑一遍试试。

先简单写一下,大致列一下,周末时间来完成这个,完成后删除这句话

二叉树

1.我的二叉树的代码:

二叉树节点

package data.structure.binarytree.model;


/**
 * 二叉树的节点数据结构
 */
public class TreeNode {

    //值
    private  int value;

    //左孩子
    private TreeNode leftChild;

    //右孩子
    private TreeNode rightChild;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public TreeNode getLeftChild() {
        return leftChild;
    }

    public void setLeftChild(TreeNode leftChild) {
        this.leftChild = leftChild;
    }

    public TreeNode getRightChild() {
        return rightChild;
    }

    public void setRightChild(TreeNode rightChild) {
        this.rightChild = rightChild;
    }

    public TreeNode(int value) {
        this.value = value;
    }
}

二叉树:

package data.structure.binarytree.model;

import java.util.LinkedList;
import java.util.Queue;

public class BinaryTree {

   //根结点
   private TreeNode root=null;

   public BinaryTree(){}

   public BinaryTree(TreeNode root) {
       this.root = root;
   }

   /**
    *  清除子树
    */
   public void clear(TreeNode node){
       if (node !=null){
           clear(node.getLeftChild());
           clear(node.getRightChild());
           node = null;//清除节点
       }
   }

   /**
    *  清除根结点
    */
   public void clear(){
       clear(root);
   }

   /**
    * 判断是否为空
    */
   public boolean isEmpty(){
       return root == null;
   }

   /**
    * (递归)获取以某节点的树高(DFS)
    * @param node
    * @return
    */
   public int hightRecursion(TreeNode node){

       if (node == null){
           return 0;//当前节点为null则树高为0
       }else{
           int l = hightRecursion(node.getLeftChild());//递归获取左子树的树高
           int r = hightRecursion(node.getRightChild());//递归获取右子树的树高
           return l > r? (l+1) : (r+1);//左右子树高的为树高+自身这一层
       }

   }

   /**
    * (非递归)获取以某节点的树高(BFS)
    * @param node
    * @return
    */
   public int hight(TreeNode node){

       if (node == null){
           return 0;//当前节点为null则树高为0
       }
       int treeHight = 0;

       Queue<TreeNode> tempNode = new LinkedList<>();
       tempNode.offer(node);
       while (!tempNode.isEmpty()){
           int count = tempNode.size();
           while (count > 0){
               node = tempNode.poll();
               if (node.getLeftChild() != null){
                   tempNode.offer(node.getLeftChild());
               }
               if (node.getRightChild() != null){
                   tempNode.offer(node.getRightChild());
               }
               count--;
           }
           treeHight++;

       }

       return treeHight;

   }

   /**
    * 获取树高
    * @return
    */
   public int hight(){
       return hight(root);
   }


   /**
    * 获取某子数的节点数
    * @param node
    * @return
    */
   public int size(TreeNode node){
       if (node == null){
           return 0;//当前节点为null则节点数为0
       }else{
           //当前节点+左子树节点数+右子树节点数
           return 1 + size(node.getLeftChild())+size(node.getRightChild());
       }
   }

   /**
    * 当前树的节点数
    * @return
    */
   public int size(){
       return size(root);
   }

   /**
    * 寻找某节点在某子树中的父亲节点(还可以在node中增加parent字段来解决)
    * @param subTree
    * @param node
    * @return
    */
   public TreeNode getParent(TreeNode subTree, TreeNode node){
       if (subTree == null){
           return null;//子树为null
       }

       if (subTree.getLeftChild() == node || subTree.getRightChild() == node){
           return subTree;
       }
       TreeNode parent;
       parent = getParent(subTree.getLeftChild(),node);//从左子树中找寻

       if (parent != null){
           return  parent;
       }
       parent = getParent(subTree.getRightChild(), node);//从右子树找寻

       return parent;
   }

   /**
    * 从树中找节点的父节点
    * @param node
    * @return
    */
   public TreeNode getParent(TreeNode node){
       return getParent(root,node);
   }

   /**
    * 是否是平衡二叉树
    * @param node
    * @return
    */
   public  boolean isBalanced(TreeNode node){
       
       int hight = higthForBalance(root);
       if ( hight >= 0){
           return true;
       }
       return false;

   }

   /**
    * 自底向上判断,如果存在而左右子树树高相差大于1的则是不平衡,最后输出-1;如果是平衡的,则是正常树高>=0
    * @param node
    * @return
    */
   private int higthForBalance(TreeNode node){
       if (node == null){
           return 0;
       }

       int leftHight = higthForBalance(node.getLeftChild());
       int rightHight = higthForBalance(node.getRightChild());

       if (leftHight == -1 || rightHight == -1 || Math.abs(leftHight-rightHight) >1){
           return -1;
       }else {
           return leftHight > rightHight ?(leftHight+1) : (rightHight+1);
       }

   }

   public TreeNode getRoot() {
       return root;
   }

   public void setRoot(TreeNode root) {
       this.root = root;
   }



}

二叉树相关的遍历

package data.structure.binarytree.algorithm;

import data.structure.binarytree.model.BinaryTree;
import data.structure.binarytree.model.TreeNode;

import java.util.*;

public class BinaryTreeTraversal {


    /**
     * 先序遍历(递归) 根结点 ---> 左子树 ---> 右子树
     *
     * @param root
     */
    public void preorderTraversalRecursion(TreeNode root) {

        if (root != null) {
            System.out.println(root.getValue() + " ");
            preorderTraversalRecursion(root.getLeftChild());
            preorderTraversalRecursion(root.getRightChild());
        }

    }

    /**
     * 先序遍历(非递归) 根结点 ---> 左子树 ---> 右子树
     *
     * @param root
     */
    public void preorderTraversal(TreeNode root) {
        Stack<TreeNode> tempNode = new Stack<>();
        TreeNode currentNode = root;

        while (currentNode != null || !tempNode.isEmpty()) {

            //左子树
            while (currentNode != null) {
                System.out.println(currentNode.getValue());
                tempNode.push(currentNode);
                currentNode = currentNode.getLeftChild();
            }
            //右子树
            currentNode = tempNode.pop().getRightChild();
        }

    }

    /**
     * 中序遍历(递归) 左子树---> 根结点 ---> 右子树
     *
     * @param root
     */
    public void inorderTraversalRecursion(TreeNode root) {

        if (root != null) {
            inorderTraversalRecursion(root.getLeftChild());
            System.out.println(root.getValue() + " ");
            inorderTraversalRecursion(root.getRightChild());
        }

    }

    /**
     * 中序遍历(递归) 左子树---> 根结点 ---> 右子树
     *
     * @param root
     */
    public void inorderTraversal(TreeNode root) {

        Stack<TreeNode> tempNode = new Stack<>();
        TreeNode currentNode = root;

        while (currentNode != null || !tempNode.isEmpty()) {

            while (currentNode != null) {
                tempNode.push(currentNode);
                currentNode = currentNode.getLeftChild();
            }
            TreeNode popNode = tempNode.pop();
            System.out.println(popNode.getValue());
            currentNode = popNode.getRightChild();
        }

    }

    /**
     * 后序遍历(递归) 左子树 ---> 右子树 ---> 根结点
     *
     * @param root
     */
    public void postorderTraversalRecursion(TreeNode root) {

        if (root != null) {
            postorderTraversalRecursion(root.getLeftChild());
            postorderTraversalRecursion(root.getRightChild());
            System.out.println(root.getValue() + " ");
        }

    }

    /**
     * 后序遍历(非递归) 左子树 ---> 右子树 ---> 根结点
     *
     * @param root
     */
    public static void postorderTraversal(TreeNode root) {

        Stack<TreeNode> tempNode = new Stack<>();
        TreeNode currentNode = root;
        TreeNode preNode = null;


        while (currentNode != null || !tempNode.isEmpty()) {

            //左子树
            while (currentNode != null) {
                tempNode.push(currentNode);
                currentNode = currentNode.getLeftChild();
            }
            TreeNode popNode = tempNode.pop();
            currentNode = popNode.getRightChild();
            //当前节点右子树不为空(1.还未遍历右子树;2.已经遍历过右子树了,通过preNode是否与当前右子树根结点相同来判断)
            if (currentNode != null && preNode != popNode.getRightChild()) {
                tempNode.push(popNode);
            } else {
                System.out.println(popNode.getValue());
                //记录打印的值
                preNode = popNode;
                currentNode = null;
            }
        }

    }

    /**
     * 后序遍历(递归) 左子树 ---> 右子树 ---> 根结点
     *
     * @param root
     */
    public void maxPathNum(TreeNode root) {

        if (root != null) {
            maxPathNum(root.getLeftChild());
            maxPathNum(root.getRightChild());
            System.out.println(root.getValue());

        }
    }

    private int  maxSum = Integer.MIN_VALUE;

    /**
     * 给你一个二叉树的根节点 root ,返回其最大路径和。
     *
     * @param root
     * @return
     */
    public  int maxPathSum(TreeNode root) {
        maxGain(root);
        return maxSum;
    }

    public  int maxGain(TreeNode node) {
        if (node == null) {
            return 0;
        }

        // 递归计算左右子节点的最大贡献值
        // 只有在最大贡献值大于 0 时,才会选取对应子节点
        int leftGain = Math.max(maxGain(node.getLeftChild()), 0);
        int rightGain = Math.max(maxGain(node.getRightChild()), 0);

        // 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
        int priceNewpath = node.getValue() + leftGain + rightGain;

        // 更新答案
        maxSum = Math.max(maxSum, priceNewpath);

        // 返回节点的最大贡献值(只能选择一边,对于它的父节点而言,这条路径要么经过当前节点的左孩子,要么经过右孩子)
        return node.getValue() + Math.max(leftGain, rightGain);
    }

//    public  int maxPathSum2(TreeNode root) {
//        int result = maxPathSumCount(root);
//        return Math.max(maxSum,result);
//    }
//
//    public  int maxPathSumCount(TreeNode root) {
//        if (root == null) {
//            return 0;
//        }
//        int leftMax = Math.max(maxPathSumCount(root.getLeftChild()), 0);
//        int rightMax = Math.max(maxPathSumCount(root.getRightChild()), 0);
//        maxSum = Math.max((root.getValue() + leftMax + rightMax) , maxSum);
//        return root.getValue() +  Math.max(leftMax, rightMax);
//    }

//    public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//        if (root == null){
//            return null;
//        }
//
//        Stack<TreeNode> result1 = new Stack<>();
//        Stack<TreeNode> result2 = new Stack<>();
//        getAllAncestor(root,p,result1);
//        getAllAncestor(root,q,result2);
//
//
//            while (result1.size() != result2.size()){
//                if (result1.size() > result2.size()){
//                    result1.pop();
//                }
//                if (result1.size() < result2.size()){
//                    result2.pop();
//                }
//            }
//
//
//        while (result1.size() > 0){
//            TreeNode treeNode = result1.pop();
//            if (treeNode == result2.pop()){
//                return treeNode;
//            }
//        }
//        return null;
//    }

//    Stack<TreeNode> result = new Stack<>();
//    public static TreeNode  getAllAncestor(TreeNode root, TreeNode node,Queue<TreeNode> result){
//        if (root != null){
//            if (root.getValue() == node.getValue()){
//                result.offer(root);
//                return null;
//            }
//            if ((root.getLeftChild()!= null && root.getLeftChild().getValue() == node.getValue() )
//                    || (root.getRightChild()!= null && root.getRightChild().getValue() == node.getValue())){
//                result.offer(node);
//                result.offer(root);
//                return root;
//            }
//            TreeNode node1 = getAllAncestor(root.getLeftChild(),node,result);
//            if (node1 != null && root.getLeftChild().getValue() == node1.getValue()){
//                result.offer(root);
//                return root;
//            }
//
//            TreeNode node2 =getAllAncestor(root.getRightChild(),node,result);
//            if (node2 != null && root.getRightChild().getValue() == node2.getValue()){
//                result.offer(root);
//                return root;
//            }
//
//        }
//
//        return null;
//    }

    public static void  getAllAncestor(TreeNode root, TreeNode node,Stack<TreeNode> result){

        TreeNode currentNode = root;
        TreeNode preNode = null;


        while (currentNode != null || !result.isEmpty()) {

            //左子树
            while (currentNode != null) {
                result.push(currentNode);
                if (currentNode.getValue() == node.getValue()){
                    return;
                }
                currentNode = currentNode.getLeftChild();
            }
            TreeNode popNode = result.pop();
            currentNode = popNode.getRightChild();
            //当前节点右子树不为空(1.还未遍历右子树;2.已经遍历过右子树了,通过preNode是否与当前右子树根结点相同来判断)
            if (currentNode != null && preNode != popNode.getRightChild()) {
                result.push(popNode);
            } else {

                //记录打印的值
                preNode = popNode;
                currentNode = null;
            }
        }
    }


    private TreeNode ans;

    private boolean dfs(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) return false;
        boolean lson = dfs(root.getLeftChild(), p, q);
        boolean rson = dfs(root.getRightChild(), p, q);
        //两种情况:1.p,q分别在该节点的左右子树中;2.p,q其中一个节点本身,另一个节点在其子树上
        if ((lson && rson) || ((root.getValue() == p.getValue() || root.getValue() == q.getValue()) && (lson || rson))) {
            ans = root;
        }
        return lson || rson || (root.getValue() == p.getValue() || root.getValue() == q.getValue());
    }

    /**
     * 获取最早公共祖先
     * @param root
     * @param p
     * @param q
     * @return
     */
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        this.dfs(root, p, q);
        return this.ans;
    }



        public static void main(String[] args) {
        //[3,5,1,6,2,0,8,null,null,7,4]
        TreeNode nodea = new TreeNode(3);
        TreeNode nodeb = new TreeNode(5);
        TreeNode nodec = new TreeNode(1);
        TreeNode noded = new TreeNode(6);
        TreeNode nodee = new TreeNode(2);
        TreeNode nodef = new TreeNode(0);
        TreeNode nodeg = new TreeNode(8);
        TreeNode nodeh = new TreeNode(7);
        TreeNode nodei = new TreeNode(4);
        //TreeNode node3 = new TreeNode(3);

        nodea.setLeftChild(nodeb);
        nodea.setRightChild(nodec);
        nodeb.setLeftChild(noded);
        nodeb.setRightChild(nodee);
        nodec.setLeftChild(nodef);
        nodec.setRightChild(nodeg);
        nodee.setLeftChild(nodeh);
        nodee.setRightChild(nodei);

        TreeNode node5 = new TreeNode(1);
        TreeNode node1 = new TreeNode(5);
//        TreeNode result = lowestCommonAncestor(nodea,node1,node5);
//        Stack<TreeNode> result1 = new Stack<>();
//        getAllAncestor(nodea,node5,result1);
//        System.out.println(result.getValue());
//        int a = 1;
//        int b = 1;
//        if (a == 1){
//            System.out.println("aaaaaaaa");
//        }else if (b == 1){
//            System.out.println("bbbbbbbb");
//        }else {
//            System.out.println("ccccccccc");
//        }
//        System.out.println(maxPathSum(nodea));
//        node1.setRightChild(node2);
//        node2.setLeftChild(node3);
//        node2.setRightChild(node4);
//        postorderTraversal(node1);

        //[0,2,4,1,null,3,-1,5,1,null,6,null,8]
//        BinaryTree tree = new BinaryTree(node0);
//        System.out.println(tree.hight());
    }
}

leetcode上有相应的题,可以做一下:
先序遍历:在做这个题如果使用递归算法的话,需要注意要将存储结果的list传入到递归循环中,
中序遍历:同上。
后序遍历:同上。
最大深度:直接使用BinaryTree类中获取树高的方法,一个递归的是深度优先遍历,一个非递归是广度优先遍历。
是否平衡二叉树判断:我在二叉树中的代码写了一个自底向上的判断方法(isBalanced),时间复杂度为n,还可以自顶向下遍历,对每个节点的左右子树的高度进行比较(主要利用计算树高的方法),时间复杂度为n的二次方;
计算root节点最大路径和:这个题我觉得难在理解上,对于当前节点(node)而言,最大路径和只有四种情况:(最大贡献值怎么理解:空节点的最大贡献值等于 0;非空节点的最大贡献值等于节点值加上左右节点中较大贡献值的节点的贡献值;对于叶节点而言,最大贡献值等于节点值)有点绕,慢慢理解吧
1.node本身的value;
2.左右节点的最大贡献值都大于0--node.value+left.value+right.value;
3.左节点最大贡献值大于0,右节点小于0--node.value+left.value;
4.左节点最大贡献值小于0,右节点大于0--node.value+left.value
二叉树的最近公共祖先:这个题我自己写了递归和非递归的代码,思路是用栈或者队列按顺序储存两个节点的祖先节点(包含自己本身),然后将较长的队列或者栈的出队或者出栈到较小长度的队列或者栈的长度,然后一起出队或者出栈,相同的第一个相同的节点就是最近公共祖先,但是结果不尽人意,递归的方法比官方的递归方法多一毫秒,所以我还是注释掉了自己的代码,留下了官方的代码:

   private TreeNode ans;

    private boolean dfs(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) return false;
        boolean lson = dfs(root.getLeftChild(), p, q);
        boolean rson = dfs(root.getRightChild(), p, q);
        //两种情况:1.p,q分别在该节点的左右子树中;2.p,q其中一个节点本身,另一个节点在其子树上
        if ((lson && rson) || ((root.getValue() == p.getValue() || root.getValue() == q.getValue()) && (lson || rson))) {
            ans = root;
        }
        return lson || rson || (root.getValue() == p.getValue() || root.getValue() == q.getValue());
    }

    /**
     * 获取最早公共祖先
     * @param root
     * @param p
     * @param q
     * @return
     */
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        this.dfs(root, p, q);
        return this.ans;
    }

二叉树的层序遍历:最大深度的时候已经写过这个方法了,稍微修改一下就可以了。

public List<List<Integer>> levelOrder(TreeNode root) {
        if (root == null){
            return new ArrayList<>();
        }

        List<List<Integer>> result = new ArrayList<>();
        Queue<TreeNode> tempNode = new LinkedList<>();
        tempNode.offer(root);
        while (!tempNode.isEmpty()){
            int count = tempNode.size();
            List<Integer> tempList = new ArrayList<>();

            while (count > 0){
                root = tempNode.poll();
                tempList.add(root.val);
                if (root.left != null){
                    tempNode.offer(root.left);
                }
                if (root.right != null){
                    tempNode.offer(root.right);
                }
                count--;
            }
            result.add(tempList);
        }

        return result;
    }

二叉树的层序遍历 II:这个也是层序遍历,不过是结果逆序输出,我想到办法是使用栈,最后遍历一栈,把结果输出出来,不过官方的方案更好一点,利用了链表头插法的为常量复杂度的性质,比我的方法更快:

public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> levelOrder = new LinkedList<List<Integer>>();

        if (root == null){
            return levelOrder;
        }
        Queue<TreeNode> tempNode = new LinkedList<>();
        tempNode.offer(root);
        while (!tempNode.isEmpty()){
            int count = tempNode.size();
            List<Integer> tempList = new ArrayList<>();

            while (count > 0){
                root = tempNode.poll();
                tempList.add(root.val);
                if (root.left != null){
                    tempNode.offer(root.left);
                }
                if (root.right != null){
                    tempNode.offer(root.right);
                }
                count--;
            }
            levelOrder.add(0,tempList);//头插法
        }
        
        return levelOrder;
    }

二叉树的锯齿形层序遍历:依旧是层序遍历,我吸取了上道题利用链表头插的特性,而官方则是利用双向队列,我们都使用一个标识来判断是顺序还是逆序,每遍历一层就反转一下或者利用层数奇偶性

public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
    if (root == null){
            return new ArrayList<>();
        }

        List<List<Integer>> result = new ArrayList<>();
        Queue<TreeNode> tempNode = new LinkedList<>();
        tempNode.offer(root);
        boolean isOrderLeft = false;
 
        while (!tempNode.isEmpty()){
            int count = tempNode.size();
            List<Integer> tempList = new  LinkedList<>();
            
            while (count > 0){
                root = tempNode.poll();
                if(isOrderLeft){
                    tempList.add(0,root.val);
                }else{
                    tempList.add(root.val);
                }            
                if (root.left != null){
                    tempNode.offer(root.left);
                }
                if (root.right != null){
                    tempNode.offer(root.right);
                }
                count--;
            }
            isOrderLeft = !isOrderLeft;
            result.add(tempList);
        }

        return result;
    }

验证二叉搜索树:通过不断缩小边界来判断,对于root节点,边界为正负无穷,对于root的左子树而言,边界为负无穷到root.val,对于右子树而言,边界为root.val到正无穷。

/**
     * 验证是否是搜索二叉树(不断缩小边界来判断)
     * @param root
     * @return
     */
    public static boolean isValidBST(TreeNode root) {
        if (root == null){
            return true;
        }

        return isValidBST(root,Integer.MAX_VALUE,Integer.MIN_VALUE);

    }

    public static boolean isValidBST(TreeNode root,int maxValue,int minValue) {
        if (root == null) {
            return true;
        }

        if (root.getValue() <= minValue || root.getValue() >= maxValue){
            return false;
        }

        return isValidBST(root.getLeftChild(),maxValue,root.getValue())&&isValidBST(root.getRightChild(),root.getValue(),minValue);
    }

二叉搜索树中的插入操作:

/**
     * 插入搜索二叉树
     * @param root
     * @param val
     * @return
     */
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null){
            return new TreeNode(val);
        }

        if (val < root.getValue()){
            root.setLeftChild(insertIntoBST(root.getLeftChild(),val));
        }else{
            root.setRightChild(insertIntoBST(root.getRightChild(),val));

        }

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

推荐阅读更多精彩内容