手撕链表

 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };

考察链表的题目不会要求我们时间复杂度,因为链表并不像是数组那样,可以方便的使用各种排序算法和查找算法。
因为链表涉及到大量的指针操作,所以链表的题目考察的主要是两个方面:代码的鲁棒性和简洁性。
不要一开始想到思路就开始写代码,最好是先想好测试用例,然后再让自己的代码通过所有的测试用例。
创建节点:ListNode* node= new ListNode();
删除删除节点:delete node; node = nullptr

【面试题05:从尾到头打印链表】

题目:输入个链表的头结点,从尾到头反过来打印出每个结点的值。
思路: 1、栈。入栈节点;出栈打印。 2、递归。

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        stack<ListNode*> nodes;
        ListNode* pNode = head;
        vector<int> a;
        while(pNode != nullptr){
            nodes.push(pNode);
            pNode = pNode->next;
        }
        while(!nodes.empty()){
            pNode = nodes.top();
            a.push_back(pNode->val);
            nodes.pop();
        }
        return a;
    }
};

【面试题13:在O(1)时间删除链表结点】

题目:给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点。

分类:
1、如果要删除的结点位于链表的尾部,那么它就没有下一个结点,这时我们就必须从链表的头结点开始,顺序遍历得到该结点的前序结点,并完成删除操作。pNode->next = nullptr; delete pToBeDeleted; pToBeDeleted = nullptr;
2、如果链表中只有一个结点,而我们又要删除链表的头结点,也就是尾结点,delete pToBeDeleted; pToBeDeleted = nullptr; *pHead=nullptr。
3、一般情况,记录下一节点,复制到该节点,并删除下一节点。

void DeleteNode(ListNode** pListHead, ListNode* pToBeDeleted)
{
    if (!pListHead || !pToBeDeleted)
        return;
    if (pToBeDeleted->m_pNext != NULL)
    {
        ListNode* pNext = pToBeDeleted->m_pNext;
        pToBeDeleted->m_nValue = pNext->m_nValue;
        pToBeDeleted->m_pNext = pNext->m_pNext;
        delete pNext;
        pNext = NULL;
    }
    //链表只有一个结点,删除头结点(也是尾结点)
    else if(*pListHead == pToBeDeleted)
    {
        delete pToBeDeleted;
        pToBeDeleted = NULL;
        *pListHead = NULL;
    }
    //要删除的结点是尾结点
    else{
        ListNode* pNode = *pListHead;
        while (pNode->m_pNext != pToBeDeleted) 
            pNode = pNode->m_pNext;

        pNode->m_pNext = NULL;
        delete pToBeDeleted;
        pToBeDeleted = NULL;
    }
}

【面试题15:链表中倒数第k个结点】 Remove Nth Node From End of List

分三种情况:
1、空链表以及n=0,无效返回nullptr;
2、计算节点间隔,定义快节点(并判断n值是否有效),然后通过遍历快慢节点,确定待删节点
1、待删节点为头结点;
2、非头节点;ps:删除节点

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        if(head ==nullptr || n == 0)
            return nullptr;
        ListNode* p1 = head;
        ListNode* p2 = head;  
        ListNode* p2Pre = nullptr;
        for (int i = 0;i<n;i++){
            if (p1 == nullptr)
                return nullptr;
            else
                p1 = p1->next; 
        }//提前走n步,并判断n值是否在有效区间内
        while(p1 != nullptr){
            p1 = p1->next; 
            p2Pre = p2;
            p2 = p2->next;
        }//同步遍历,并记录删除节点的上一节点
        if(p2Pre == nullptr){
            head = p2->next;
        }
        else{
            p2Pre->next = p2->next;
        }//判断删除节点是否为首节点 
        free(p2);//删除节点;
        return head;
       
    }
};

链表有环问题:是否有环Linked List Cycle,环入口节点

用两个指针去遍历,一个指针一次走两步,一个指针一次走一步,如果有环,两个指针肯定会在环中相遇。相遇点即为环内某个节点。时间复杂度为O(n)。
环入口两种思路:
1、采用两个指针,一快一慢相隔环长度节点,相遇即为入口节点。环长度根据上面判断是否有环的相遇点计算,相遇点出发到在此回到该节点时计数。
2、在上面的相遇节点处断开(当然函数结束时不能破坏原链表),这样就形成了两个相交的单链表,求进入环中的第一个节点也就转换成了求两个单链表相交的第一个节点。

class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode* pfast = head;
        ListNode* pslow = head;
        while(pfast != nullptr){
            pfast = pfast->next;
            if(pfast == pslow)
                return true;
            pslow = pslow->next; 
            if(pfast != nullptr)
                pfast = pfast->next;
        }
        if(pfast == nullptr)
            return false; 
    }
};
class Solution {
public:
    /*1) 确定有无环
    #2) 确定环节点数
    #3) 确定环入口节点*/
    ListNode* MeetingNode(ListNode* pHead)
    {
        if (pHead == nullptr)
            return nullptr;
        ListNode* pSlow = pHead;
        if (pSlow->next == nullptr)
            return nullptr;
        ListNode* pFast = pSlow->next;
        while(pFast!= nullptr){
            if (pFast == pSlow)
                return pFast;
            pSlow = pSlow->next;
            pFast = pFast->next;
            if (pFast != nullptr)
                pFast = pFast->next;
        }
        return nullptr;
    }
    
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        ListNode* meetingNode = MeetingNode(pHead);
        if (meetingNode == nullptr)
            return nullptr;
        int count = 1;
        ListNode* pNode = meetingNode;
        while(pNode->next != meetingNode){
            pNode = pNode->next;
            count++;
        }
        pNode = pHead;
        for (int i=0; i<count; i++)
            pNode = pNode->next;
        ListNode* pNode1 = pHead;
        while(pNode != pNode1){
            pNode = pNode->next;
            pNode1= pNode1->next;
        }
        return pNode;
    }
};

【面试题16:反转链表】

题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

需记录三个节点。可以采用辅助结点,避免考虑头结点情况。一般需要考虑当前节点的上一结点时可采用辅助头结点。

class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) { 
        ListNode* pNode = pHead; 
        ListNode* preNode = nullptr;
        ListNode* nextNode = nullptr; 
        while(pNode != nullptr){
            nextNode = pNode->next;
            pNode->next = preNode;
            
            preNode = pNode;
            pNode = nextNode;
        }
        return preNode;
    }
};

【面试题17:合并两个排序的链表】Merge Two Sorted Lists

题目:输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的

每次取两个链表的头结点进行比较;剩下的两个链表仍是排序链表,属于递归问题。

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (l1 == nullptr)
            return l2;
        else if(l2 == nullptr)
            return l1;
        ListNode* MergeHead = nullptr;
        if(l1->val>l2->val){
            MergeHead = l2;
            MergeHead->next = mergeTwoLists(l1,l2->next);
        }
        else{
            MergeHead = l1;
            MergeHead->next = mergeTwoLists(l1->next,l2);
        }
        return MergeHead;
    }
};

【面试题26:复杂链表的复制】

题目:请实现函数ComplexListNode clone(ComplexListNode head),复制一个复杂链表。在复杂链表中,每个结点除了有一个next 域指向下一个结点外,还有一个sibling 指向链表中的任意结点或者null。

1、两步:第一步复制顺序节点,第二部复制随机节点,节点的定位需要O(n)。总的时间复杂度O(nn)。
2、三步:顺序节点的复制,并顺序连接在该节点的后面;随机节点的复制根据原节点的定位;奇偶拆分链表。时间复杂度O(n).
ps:完成第一步的顺序节点复制,才能定位之后的随机节点;生成节点: ListNode* Node= new ListNode(0);

struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        CloneSequenceNode(pHead);
        CloneRandomNode(pHead); 
         
        return SeparateList(pHead);
    }
    void CloneSequenceNode(RandomListNode* pHead){
        RandomListNode* pNode = pHead;
        while(pNode != nullptr){
            RandomListNode* cloneNode = new RandomListNode(pNode->label); 
            cloneNode->next = pNode->next;
            //cloneNode->random = nullptr;
            pNode->next = cloneNode;
            pNode = cloneNode->next;
        }
    }
    void CloneRandomNode(RandomListNode* pHead){
        RandomListNode* pNode = pHead;
        while(pNode != nullptr){
            RandomListNode* cloneNode = pNode->next;
            if (pNode->random != nullptr){
                cloneNode->random = pNode->random->next;
            }
            pNode = cloneNode->next;
        }
    }
    RandomListNode* SeparateList(RandomListNode* pHead){
        RandomListNode* pNode = pHead;
        RandomListNode* cloneHead = nullptr;
        RandomListNode* clonepNode= nullptr;
        if (pNode != nullptr){
            cloneHead = pNode->next;
            clonepNode = cloneHead;
        }
        while(pNode !=nullptr ){
            pNode->next = clonepNode->next;
            pNode = pNode->next; 
            if (pNode != nullptr){
                clonepNode->next = pNode->next;
                clonepNode = clonepNode->next;  
            } 
        }
        return cloneHead;
    }
};

查找单链表的中间结点

典型的两个指针问题。定义两个指针,快指针一次走两步,慢指针一次走一步。快指针走到最后一个节点,慢指针对应的就是中间节点

【面试题37:两个链表的第一个公共结点】 intersection-of-two-linked-lists

题目:输入两个链表,找出它们的第一个公共结点。

第一个问题:是否相交。如果相交两个链表的尾节点一定相同。
第二个问题:第一个相交公共点。
1、异步遍历找相同节点。时间复杂度O(mn)
2、第一公共节点后两链表重合,从后往前遍历。采用后进先出(栈)。栈的定义:std::stack<ListNode*>nodes。时间复杂度O(m+n),空间复杂度O(m+n)
3、先计算两链表长度差,让长链表先走差步,然后同步遍历两链表找到第一个相同节点。时间复杂度O(m+n)

class Solution {
public: 
    ListNode*getIntersectionNode( ListNode* pHead1, ListNode* pHead2) {
        int Listlength1 = GetLength(pHead1);
        int Listlength2 = GetLength(pHead2);
        
        int Listlengthdiff =  Listlength1- Listlength2;
        ListNode* Listlong = pHead1;
        ListNode* Listshort = pHead2;
        if(Listlength2>Listlength1){
            Listlong = pHead2;
            Listshort = pHead1;
            Listlengthdiff = Listlength2 - Listlength1;
        }
        for (int i =0; i<Listlengthdiff;i++)
            Listlong = Listlong->next;
        while((Listlong != nullptr) && (Listshort != nullptr) && (Listlong !=Listshort)){
            Listlong = Listlong->next;
            Listshort = Listshort->next;
        }
        ListNode* ListCommonNode= Listshort;
        return ListCommonNode; 
    }
    int GetLength(ListNode* pHead){
        int length = 0;
        ListNode* pNode = pHead;
        while(pNode != nullptr){
            pNode = pNode->next;
            length = length+1;
        }
        return length;
    }
};

Add Two Numbers

题目:Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)Output: 7 -> 0 -> 8Explanation: 342 + 465 = 807.
思路:逐节点相加。注意点:1)进位问题,2)链表长短不一,3)两链表遍历完后可能仍有进位,还需循环一次。

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* pHead = nullptr;
        ListNode* pNode = pHead;
        ListNode* pNode1 = l1;
        ListNode* pNode2 = l2;
        int dedigit = 0; 
        while(pNode1 != nullptr || pNode2!=nullptr || dedigit){
            int pNode1val = pNode1 ? pNode1->val : 0;
            int pNode2val = pNode2 ? pNode2->val : 0;
            ListNode* node = new ListNode((pNode1val+pNode2val+ dedigit)%10 );
            dedigit = (pNode1val+pNode2val+ dedigit)/10;
            if(pHead == nullptr){
                pHead = node;
                ListNode* pNode = pHead;
            } 
            else 
                pNode->next = node;
            pNode = node;
            pNode1 = pNode1 ? pNode1->next : pNode1;
            pNode2 = pNode2 ? pNode2->next : pNode2;
        } 
        return pHead; 
    }
    unsigned int ListReverseDigit(ListNode* pHead){ 
        ListNode* pNode = pHead;
        unsigned int digit = 0;
        int count = 1;
        while(pNode!=nullptr){
            digit = digit+count*pNode->val;
            count = count*10;
            pNode = pNode->next;
        }
        return digit; 
    }//neglect value range of int;;
    ListNode* DigitReverseList(unsigned int digit){  
        ListNode* pHead= nullptr;
        ListNode* pNode= pHead;
        int dedigit = 1;
        int redigit = 0; 
        while(dedigit !=0 ){
            dedigit = digit/10;
            redigit = digit%10;
            digit = dedigit; 
            ListNode* node = new ListNode(redigit);
            if(pHead == nullptr)
                pHead = node;
            else
                pNode->next = node;
            pNode = node;
        } 
        return pHead;
    }
};

Remove Duplicates from Sorted List II

题目:删除链表中重复的节点。
Example 1:
Input: 1->2->3->3->4->4->5
Output: 1->2->5

1)第一个节点就为待删除节点;
2)中间节点待删除;
3)尾节点待删除
ps:增加一个头节点,不许考虑第一个节点待删除的情况。

// 三种情况:1)空;2)1-1-1,2)1-1-2, 3)1-2-2-3, 4)1-2-2     1-1-2-2-3-4-4
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (head == nullptr)
            return nullptr;
        /*ListNode* preNode = nullptr;
        ListNode* pNode = head;
        while(pNode!= nullptr){
            //判断是否有相同节点
            if (pNode->next != nullptr && (pNode->val == pNode->next->val)){
                int val = pNode->val;
                while(pNode != nullptr && (pNode->val == val))
                        pNode = pNode->next;//找到下一个不同节点
                if(preNode == nullptr)//如果重复节点被头指针指向
                    head = pNode;
                else
                    preNode->next = pNode;
            }
            else{
                preNode = pNode;
                pNode = pNode->next;
            }
        }
        return head; 
    }*/
        ListNode* prehead = new ListNode(0);
        prehead->next = head;
        ListNode* preNode = prehead;
        ListNode* pNode = head;
        while(pNode!= nullptr){
            //判断是否有相同节点
            if (pNode->next != nullptr && (pNode->val == pNode->next->val)){
                int val = pNode->val;
                while(pNode != nullptr && (pNode->val == val))
                        pNode = pNode->next;//找到下一个不同节点 
                preNode->next = pNode;
            }
            else{
                preNode = pNode;
                pNode = pNode->next;
            } 
        }
        return prehead->next; 
    }
};

Remove Duplicates from Sorted List

题目:Given a sorted linked list, delete all duplicates such that each element appear only once.
Example 1:
Input: 1->1->2
Output: 1->2

遍历整个链表,碰到下一节点的值相同,则定义下一结点指针,循环找到值不同的指针,最后该指针指向循环后的节点。

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode* Node = head;
        while(Node != nullptr){
            if (Node->next != nullptr && (Node->val == Node->next->val)){
                ListNode* pNode = Node->next;
                while (pNode->next != nullptr && (pNode->next->val == pNode->val))
                    pNode = pNode->next;
                Node->next = pNode->next; 
            }
            Node = Node->next;
        }
        return head;
    }
};

Partition List

题目:给定一个链表和一个值,要求小于这个值的结点都位于大于或等于这个值节点的前面。且保留原始节点相对位置。
Input: head = 1->4->3->2->5->2, x = 3
Output: 1->2->2->4->3->5
思路:1)找到大于给定值的第一个节点,记录该节点和上一结点。2)从该节点开始遍历,遇到小于给定值的节点,将插入到记录节点的前面。ps:中间涉及到四个指针。

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        if(head == nullptr)
            return nullptr;
        ListNode* p1 =head; 
        ListNode* p1Pre = nullptr;
        while(p1->val < x){ 
            p1Pre = p1;
            p1 = p1->next;
            if (p1 ==nullptr)
                return head;
        }
        ListNode* p2 = p1; 
        ListNode* p2Pre = p1Pre;
        while(p2 != nullptr){
            if(p2->val < x){
                if (p1Pre == nullptr)
                     head = p2; 
                else
                    p1Pre->next = p2; 
                p2Pre->next = p2->next;
                p2->next = p1;
                p1Pre = p2; 
                p2 = p2Pre->next; 
            }
            else{
                p2Pre = p2;
                p2 = p2->next;
            }
        }
        return head; 
    }
};

Swap Nodes in Pairs

题目:Given a linked list, swap every two adjacent nodes and return its head.
Example: Given 1->2->3->4, you should return the list as 2->1->4->3.
思路:三个指针。

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* p1 = head;
        ListNode* p1Pre = nullptr;
        if (p1 == nullptr ||p1->next ==nullptr)
            return head;
        ListNode* p2 = p1->next;
        while(p2 !=nullptr){
            p1->next = p2->next; 
            p2->next = p1;
            if (p1Pre == nullptr) 
                head = p2;
            else
                p1Pre->next = p2;
            p1Pre = p1;
            p1 = p1->next;
            if(p1 == nullptr)
                return head;
            else
                p2 = p1->next;
        }
        return head;
    }
};

Rotate List

题目:Given a linked list, rotate the list to the right by k places, where k is non-negative.
Example 1:
Input: 1->2->3->4->5->NULL, k = 2
Output: 4->5->1->2->3->NULL
Explanation:
rotate 1 steps to the right: 5->1->2->3->4->NULL
rotate 2 steps to the right: 4->5->1->2->3->NULL
思路:由于有周期,先计算一个周期内的K值。然后两个指针循环使用,指向最后一个结点和倒数第二个节点。

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head == nullptr)
            return nullptr;  
        ListNode* pNode = head;
        int count =1;
        while(pNode->next !=nullptr){
            count++;
            pNode = pNode->next;
        }
        k = k%count;
        while(k-- !=0){
            pNode = head;
            ListNode* preNode = nullptr;
            while(pNode->next != nullptr){
                preNode = pNode;
                pNode = pNode->next;
            }
            if(preNode == nullptr)
                return head;
            else
                preNode->next = nullptr;
            pNode->next = head;
            head = pNode; 
        } 
        return head;
    }
};

Reverse Linked List II

题目:Reverse a linked list from position m to n. Do it in one-pass.
Example:
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL
思路:1)首先找到并记录第m,m-1个结点;2)然后反转接下来的节点,直到第m个节点,同时可得到第n个节点和第n+1个节点;3)最后进行连接:m-1->next = n;m->next = n+1; pS:反转链表中有涉及到三个指针。

//leetcode,链表的第m个节点到第n个节点区间反转。
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {

        ListNode* helper = new ListNode(0);
        helper->next = head;
        ListNode* pNode = head;
        ListNode* preNode = helper; 
        int length = n-m;
        while(((m--)-1 ) && (pNode != nullptr)){
            preNode =pNode;
            pNode = pNode->next;
        } 
        if(head == nullptr || pNode == nullptr)
            return head;
        ListNode* reversestart = pNode;  
        ListNode* reversePre = preNode;
        ListNode* pNext = nullptr; 
        while(pNode !=nullptr){ 
            pNext = pNode->next;
            pNode->next = preNode; 
            if (!length--) 
                break;
            else{
                preNode = pNode;
                pNode = pNext;
            } 
        } 
        reversePre->next = pNode;
        reversestart->next = pNext;
        return helper->next;
    }
};

网易游戏-好友上下线排序(留着解决)

#include <iostream>
#include <cstdio>
#include<string>

using namespace std;

struct ListNode {
     string val;
     ListNode *next;
     ListNode(int x) : val(x), next(NULL) {}
};

ListNode* removeNode(ListNode* phead,opName){
    ListNode* pNode = phead;
    ListNode* preNode = nullptr;
    while(pNode!= nullptr){
        preNode = pNode;
        pNode= pNode->next;
    }
    if(preNode != nullptr)
        preNode->next = pNode->next;
    return pNode;
}

ListNode* addNode(ListNode* phead, ListNode* addNode){
    ListNode* helper = new ListNode('0');
    helper->next = phead;
    ListNode* pNode = phead;
    ListNode* preNode = helper;
    while(pNode!=nullptr){
        while(mapping[pNode->val] < mapping[addNode->val]){
            preNode = pNode;
            pNode = pNode->next;
        }
        while(pNode->val > addNode->val){
            preNode = pNode;
            pNode = pNode->next;
        }
        preNode->next = addNode;
        addNode->next = pNode;
    }
    return helper->next;
} 

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