剑指offer----字符串、链表

前言

c/c++把常量字符串放到单独的一个内存区域。当几个指针赋值给相同的常量字符串时,他们实际上会指向相同的内存地址:

int main()
{
    char str1[] = "hello world";
        char str2[] = "helle world";
        char* str3 = "hello world";
        char* str4 = "hello world";
        
        if(str1 == str2)
            cout << "str1 and str2 are same.\n";
        else
            cout << "str1 and str2 are not same.\n";

        if(str3==str4)
            cout << "str3 and str4 are same.\n";
        else
            cout << "str3 and str4 are not same.\n";

        return 0;   
}


 ./main
str1 and str2 are not same.
str3 and str4 are same.

第一个不同是因为两个不同的数组地址;第二个相同是因为常量字符串在内存中只有一个拷贝,他们都指向同一地址。

  1. 替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

  • 解析:先计算增大串长后的长newStrLength,用指针2指向该位置,同时指针1指向未增长时串中字符的结尾'\0',从后遍历复制指针1、2上的字符。
class Solution {
public:
    void replaceSpace(char *str,int length) {
        if(str==nullptr || length<=0)
            return;
        int strLength=0, space=0;
        //先求替换后的字符串大小
        while(str[strLength]!='\0')
        {
            
            if(str[strLength]==' ')
                ++space;
            ++strLength;
        }
        //strLength指向终止符处
        //增大后的串长
        int newStrLength = strLength+2*space;
        if (newStrLength > length)//length为该串总容量
            return;
        while(strLength>=0 && newStrLength>strLength)
        {
            if(str[strLength]==' ')
            {
                str[newStrLength--] = '0';
                str[newStrLength--] = '2';
                str[newStrLength--] = '%';
            }
            else
            {
                str[newStrLength--]=str[strLength]; 
            }
            --strLength;
        }
    }
};

19、正则表达式

请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

  • 解:当遇到*的时候可以当做前面的字符(一个字符)出现了0次,也就是忽略*直接前移2步,也可以当做出现n次,在原处待着不动,让str前移n步去比较;退出条件是看str是否为空且模式也为空就是匹配上,否则没有匹配上,递归的调用看各种情况下返回的是否有一个满足条件。
class Solution {
public:
    bool match(char* str, char* pattern)
    {
        if(str==nullptr || pattern==nullptr)
            return false;
        return matchCore(str, pattern);
    }
private:
    bool matchCore(char* str, char* pattern)
    {
    //若同时结束对比为匹配
    if(*str=='\0' && *pattern=='\0')
        return true;
    
    if(*str!='\0' && *pattern=='\0')
        return false;
    
    if(*(pattern+1)=='*')//若下一个字符为需要匹配的字符
    {
        //当前以及匹配
        if(*pattern==*str || (*pattern =='.' && *str!='\0'))
        {    
            //move on the next state || stay on current state || 向前移动2步,忽略一个‘*’匹配;
            return matchCore(str+1, pattern+2) || matchCore(str+1,pattern) || matchCore(str, pattern+2);
        }
        else
            //向前移动2步,忽略一个‘*’匹配;
            return matchCore(str,pattern+2);
    }
    // 当前字符以及匹配,去往下面的字符;
    if (*str==*pattern || (*pattern=='.' && *str!='\0'))
        return matchCore(str+1, pattern+1);
    return false;
    }  
};

38、字符串的排列

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

  • 解析:第一个字符固定为i,剩下其他字符的全排列在后面;i的取值是整个字符串的取值,因此,每次交换头字符,还有后面字符串中的下一个字符;递归结束条件是该字符串已经找到;
class Solution {
public:
    vector<string> Permutation(string str)
    {
        vector<string> result;
        if(str.empty()) return result;
         
        Permutation(str,result,0);
         
        // 此时得到的result中排列并不是字典顺序,可以单独再排下序
        sort(result.begin(),result.end());
         
        return result;
    }
     
    void Permutation(string str,vector<string> &result,int begin)
    {
        if(begin == str.size()-1) // 递归结束条件:索引已经指向str最后一个元素时
        {
            if(find(result.begin(),result.end(),str) == result.end())
            {
                // 如果result中不存在str,才添加;避免aa和aa重复添加的情况
                result.push_back(str);
            }
        }
        else
        {
            // 第一次循环i与begin相等,相当于第一个位置自身交换,关键在于之后的循环,
            // 之后i != begin,则会交换两个不同位置上的字符,直到begin==str.size()-1,进行输出;
            for(int i=begin;i<str.size();++i)
            {
                swap(str[i],str[begin]);
                Permutation(str,result,begin+1);
                swap(str[i],str[begin]); // 复位,用以恢复之前字符串顺序,达到第一位依次跟其他位交换的目的
            }
        }
    }
     
    void swap(char &fir,char &sec)
    {
        char temp = fir;
        fir = sec;
        sec = temp;
    }
};


链表

前言

  • 内存分配不是在创建链表时一次完成的,而是每次添加一个节点是分配内存;因此没有闲置的内存,链表的空间效率比数组高。
  • 指针的指针:
// Example program
#include <iostream>
#include <string>
#include<vector>
using namespace std;

int main()
{
    int i=1;
    int *pi = &i;
    int **ppi = &pi;
    cout<<"*pi :" << *pi << endl;
    cout<<"&pi :" << &pi << endl;
    cout <<"*ppi :" << *ppi<<endl;
    return 0;   
}

*pi :1
&pi :0x70aa208f64e8
*ppi :0x70aa208f64e4
  • 链表的尾部添加节点和删除值为某数的节点如下:
// Example program
#include <iostream>
#include <string>
#include<vector>
using namespace std;

struct ListNode
{
    int value;
    ListNode *pNext;
};
//pHead是二级指针,指向指针的指针
void AddToTail(ListNode** pHead,int value)
{
    ListNode* pNew = new ListNode();
    pNew->value = value;
    pNew->pNext = nullptr;
    
    //是否为根节点
    if((*pHead)==nullptr)
    {
        //取出头指针指向当前新节点
        *pHead = pNew;
    }
    else
    {
        ListNode *pNode=*pHead;
        //通过指针链接新节点在尾部
        while(pNode->pNext!=nullptr)
                    pNode = pNode->pNext;
        pNode->pNext =pNew;
    }
}

//删除某值元素
void RemoveNode(ListNode** pHead, int value)
{
    if(pHead==nullptr || *pHead==nullptr)
                return;
    //指向要删除的元素标记指针
    ListNode* pToBeDeleted = nullptr;
    
    
    //判断是否删除位置在头结点
    if((*pHead)->value == value)
    {
        //标记
        pToBeDeleted = *pHead;
        //新的头结点位置在下一个位置
        *pHead=(*pHead)->pNext;
    }
    else
    {
        //根节点的地址
        ListNode* pNode=*pHead;
        while(pNode->pNext != nullptr
        && pNode->pNext->value!=value)
            pNode=pNode->pNext;
        //找到该元素的位置,为pNode的下一个位置
        if(pNode->pNext!=nullptr && pNode->pNext->value==value)
        {
            //该元素位置下一个位置赋给pToBeDeleted
            pToBeDeleted = pNode->pNext;
            //删除元素前一个位置的pNext链接到删除元素的下一个位置;之后就可以安全的删除了
            pNode->pNext = pNode->pNext->pNext;
        }
    }
    //删除该标记指针
    if(pToBeDeleted!=nullptr)
    {
        delete pToBeDeleted;
        pToBeDeleted = nullptr; //避免出错,赋为空
    }

}
int main()
{
        ListNode *test;
        ListNode** PP = &test;
        AddToTail(PP, 20);
        cout << test->value << endl;
        AddToTail(PP, 30);
        cout << test->pNext->value << endl;
        RemoveNode(PP,20);
        cout << test->value << endl;
        return 0;   
}

20
30
30
  1. 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList
class Solution {
public:
    //递归求解,或者用栈来求解。
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> ans;
        stack<ListNode*> st;
        while(head!=nullptr)
        {
            st.push(head);
            head = head->next;
        }
        while(!st.empty())
        {
            ans.push_back(st.top()->val);
            st.pop();
        }
        return ans;
            
    }
  1. 删除链表中重复的元素

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

class Solution {
public:
    //需要三个指针前中后
    ListNode* deleteDuplication(ListNode* pHead)
    {
        if(pHead==nullptr) return nullptr;
        ListNode *pPreNode = nullptr; //前一个节点
        ListNode *pNode = pHead; //当前节点
        while(pNode!=nullptr)
        {
            ListNode * pNextNode = pNode->next;//重置为当前节点的下一节点
            bool needDelete=false;
            //下一节点和当前节点是否是重复的
            if(pNextNode!=nullptr && pNode->val==pNextNode->val)
                needDelete = true;
            
            if(!needDelete)//没有重复,往下走
            {
                pPreNode = pNode;
                pNode = pNode->next;
            }
            else //重复节点
            {
                //取出值,删除连续等于该值的节点
                int value = pNode->val;
                ListNode* pToBeDel = pNode;
                //连续删除
                while(pToBeDel != nullptr && pToBeDel->val == value)
                {
                    pNextNode = pToBeDel->next;
                    delete pToBeDel;
                    pToBeDel = nullptr;
                    pToBeDel = pNextNode;
                }
            //确定是否是头结点
            if(pPreNode == nullptr)
                pHead = pNextNode;
            else//删除之后重链接删除后的节点
                pPreNode->next = pNextNode;
            pNode=pNextNode;
            }
        }
        return pHead;
    }
};
  1. 输入一个链表,输出该链表中倒数第k个结点。
  • 双指针开始走,第一个走到k-1步时,第二个开始从根节点走。判断链长是否有k,没有解返回。
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(!pListHead || k==0) return nullptr;
        ListNode* preListNode=nullptr;
        ListNode* curListNode=pListHead;
        //第一个指针走了k-1步,加上本身是一个位移,总共k位移,第二个指针开始从头结点走1步
        for(unsigned i=1;i<k;++i)
        {
            if(curListNode->next!=nullptr)
            {
                curListNode=curListNode->next;
            }
            else //链表长度不足
            {
                return nullptr;
            }
        }
        //开始走
        preListNode = pListHead;
        //下一个节点指针非空
        while(curListNode->next!=nullptr)
        {
            curListNode=curListNode->next;
            preListNode=preListNode->next;
        }
        return preListNode;
    }
};

23.链表中环的入口节点

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

解:1. 确定链表是否有环;(设置一个走得快的指针是否能追上走得慢的指针;)
2. 环的大小是多少;
3. 快指针先走环的大小步数,慢指针再走,必然在环的入口处相遇。

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        //meetingnode返回该链表是否有环,有的情况下,返回快慢指针相遇的节点
        ListNode* ListMeetNode=MeetingNode(pHead);
        if(ListMeetNode==nullptr)
            return nullptr;
        int countLoop=1;
        ListNode* pNode = ListMeetNode;
        while(pNode->next!=ListMeetNode)
        {
            countLoop++;
            pNode=pNode->next;
        }
        pNode=pHead;
        ListNode *slowNode=pHead;
        //先走k-1步
        for(int i=0;i<countLoop;++i)
        {
            pNode=pNode->next;
        }
        while(pNode!=slowNode)
        {
            pNode=pNode->next;
            slowNode=slowNode->next;
        }
        return slowNode;
    }
private:
    ListNode* MeetingNode(ListNode* head)
    {
        if(head == nullptr)//空链表的情况
            return nullptr;
        ListNode* pslow=head->next;
        if(pslow==nullptr)//无环的情况
            return nullptr;
        ListNode* pfast=pslow->next;//快一步
        while(pfast!= nullptr && pslow!=nullptr)
        {
            if(pfast==pslow)//有环
                return pfast;
            pslow = pslow->next;
            pfast = pfast->next;
            if(pfast!=nullptr)//多走一步
                pfast=pfast->next;
        }
        return nullptr;
    }
};

35、复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

  • 解析:重复各个节点,然后关联新的重复节点的random,再然后重链接取出偶数链接的链表。
class Solution {
public:
    //复制原始链表的任一节点N并创建新节点N',再把N'链接到N的后边
    void CloneNodes(RandomListNode* pHead)
    {
        RandomListNode* pNode=pHead;
        while(pNode!=NULL)
        {
            RandomListNode* pCloned=new RandomListNode(0);
            pCloned->label=pNode->label;
            pCloned->next=pNode->next;
            pCloned->random=NULL;
              
            pNode->next=pCloned;
              
            pNode=pCloned->next;
        }
    }
    //如果原始链表上的节点N的random指向S,则对应的复制节点N'的random指向S的下一个节点S'
    void ConnectRandomNodes(RandomListNode* pHead)
    {
        RandomListNode* pNode=pHead;
        while(pNode!=NULL)
        {
            RandomListNode* pCloned=pNode->next;
            if(pNode->random!=NULL)
                pCloned->random=pNode->random->next;
            pNode=pCloned->next;
        }
    }
    //把得到的链表拆成两个链表,奇数位置上的结点组成原始链表,偶数位置上的结点组成复制出来的链表
    RandomListNode* ReConnectNodes(RandomListNode* pHead)
    {
        RandomListNode* pNode=pHead;
        RandomListNode* pClonedHead=NULL;
        RandomListNode* pClonedNode=NULL;
          
        //初始化
        if(pNode!=NULL)
        {
            pClonedHead=pClonedNode=pNode->next;
            pNode->next=pClonedNode->next;
            pNode=pNode->next;
              
        }
        //循环
        while(pNode!=NULL)
        {
            pClonedNode->next=pNode->next;
            pClonedNode=pClonedNode->next;
            pNode->next=pClonedNode->next;
            pNode=pNode->next;
        }
          
        return pClonedHead;
          
    }
    //三步合一
    RandomListNode* Clone(RandomListNode* pHead)
    {
        CloneNodes(pHead);
        ConnectRandomNodes(pHead);
        return ReConnectNodes(pHead);
    }
};

52、两个链表的第一个公共节点

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

  • 解: 方法1:对链表1中每一个节点,都遍历一遍链表2,复杂度为O(mn);m\n分别为两个链表的长度;
    方法2:若中间某一个节点相同,之后剩下的节点都是一样的地址存在,因此结尾处都一样,
    设置栈结构,从尾部排除,遇到不相等的元素时,之前的那个元素便是第一个相同的元素点,空间换时间
    的O(m+N)空间换取时间为O(m+n);
    方法3:先遍历两个链表得到最长链表的长度s1与短链表的长度s2,在最长链表上先移动s1-s2,再同时移动
    链表1,2,且不断比较直到相等;

方法3的原因是:链表A长度是LA,链表B长度是LB,他们的公共部分长度是LC,那么不妨设LA长度更长,那么有:LA>LB \ge LC,那么AB的公共部分至少在A后面的长度还有B这么长的时候才有可能。

public:
    /*
    */
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if(!pHead1 || !pHead2) return nullptr;
        ListNode *pDupHead1 = pHead1;
        ListNode *pDupHead2 = pHead2;
        int  count1=0, count2=0;
        while(pHead1)
        {
            count1++;
            pHead1=pHead1->next;
        }
        while(pHead2)
        {
            count2++;
            pHead2=pHead2->next;
        }
        if(count1>count2) //链表1最长
        {
            int lCount = count1 - count2;
            while(lCount--)
                pDupHead1=pDupHead1->next;
        }
        else
        {
            int lCount = count2 - count1;
            while(lCount--)
               pDupHead2 = pDupHead2->next; 
        }
        while(pDupHead1 && pDupHead2 && (pDupHead1!=pDupHead2))
        {
            pDupHead1 = pDupHead1->next;
            pDupHead2 = pDupHead2->next;
        }
        ListNode * pFirstCommonNode = pDupHead1;
        return pFirstCommonNode;
    }
};

50、第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).

  • :方法1:暴力求解,对当前每一个字符,搜索后面的真个字符串,复杂度是O(n^2);
    方法2:哈希表:自建一个简单哈希表;
    可以把哈希表设为256,因为char是8bit的类型,总共只有256个字符,
    可以设置哈希表为负,第一次插入后为正,再次插入同样的字符,设为负,下次只有找出数组非负的位置便是对应的第一次出现的字符
class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        if(str.empty()) return -1;
        vector<int> arr(26*2,0);
        for(auto i:str)
        {
            if('a'<=i && i<='z')
                arr[int(i-'a')]+=1;
            else
                arr[int(i-'A')+26]+=1;
        }
        
        
        for(int j=0; j<str.size(); ++j)
        {
            int numj;
            if('a'<=str[j] && str[j]<= 'z')
                numj=int( str[j]-'a');
            else
                numj=int( str[j]-'A'+26);
            if(arr[numj] == 1)
                return j;
        }
    }

};

58、反转单词顺序字符串

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

  • 先反转整个串,再反转每一个单词;
class Solution {
public:
    string ReverseSentence(string str) {
        if(str.empty()) return str;
        int begin=0,end=0;
        reverse(str.begin(),str.end());
        int size = str.size();
        while(begin<size)
        {
            //起点为空,重置游标
            while(begin<size && str[begin]==' ') begin++;
            end=begin;
            //终点不为空,一直往前走到头
            while(end<size && str[end]!=' ') end++;
            reverse(str.begin()+begin, str.begin()+end);
            //反转之后,起点的顺序是重点的顺序
            begin = end;
        }
        return str;
    }
};

2。左旋转字符串

字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

  • 先翻转这个串的前后两部分,然后再全部一次性翻转
class Solution {
public:

    string LeftRotateString(string str, int n) {
        if(str.empty() || n<=0) return str;
        reverse(str.begin(),str.begin()+n);
        reverse(str.begin()+n,str.end());
        reverse(str.begin(),str.end());
        return str;
    }
};

67、将一个字符串转换成一个整数

将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。

public:
    int StrToInt(string str) {
        long long int num = 0;
        if(str.empty()) return num;
        int minus;
        if(str[0] == '+')
            minus = 1;
        if(str[0] == '-')
            minus = -1;
        int i;
        if(str[0]!='+' && str[0]!='-') i=0;
        else i=1;
        for(;i<str.size();++i)
        {           
            if(str[i]>='0' && str[i]<='9')
            {
                num = num * 10 + minus * (str[i]-'0');
            }
            else
            {
                num = 0;
                break;
            }
        }
        return (int)num; //类型转换
    }
};

50、字符流中第一个出现的字符

方法1:用常规方法来解:

class Solution
{
public:
  //Insert one char from stringstream
    string str;
    //全部初始化为0
    int hash[256]= {0};
    void Insert(char ch)
    {
        str+=ch;
        hash[ch]++;
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
        int size = str.size();
        for(int i=0; i<size; ++i)
        {
            if(hash[str[i]]==1)
                return str[i];
        }
        return '#';
    }
};

方法2:用stl来解:

class Solution
{
public:
  //Insert one char from stringstream
    string str;
    map<char,int> m;    //用map来记录字符出现的次数
    void Insert(char ch)
    {
        str += ch;
        m[ch]++;
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
        for(auto it : str)
        {
            if(m[it] == 1)
            {
                return it;
            }
        }
        return '#';
    }

};

、请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

class Solution {
public:
    bool isNumeric(char* str) {
        // 标记符号、小数点、e是否出现过
        bool sign = false, decimal = false, hasE = false;
        for (int i = 0; i < strlen(str); i++) {
            if (str[i] == 'e' || str[i] == 'E') {
                if (i == strlen(str)-1) return false; // e后面一定要接数字
                if (hasE) return false;  // 不能同时存在两个e
                hasE = true;
            } else if (str[i] == '+' || str[i] == '-') {
                // 第二次出现+-符号,则必须紧接在e之后
                if (sign && str[i-1] != 'e' && str[i-1] != 'E') return false;
                // 第一次出现+-符号,且不是在字符串开头,则也必须紧接在e之后
                if (!sign && i > 0 && str[i-1] != 'e' && str[i-1] != 'E') return false;
                sign = true;
            } else if (str[i] == '.') {
              // e后面不能接小数点,小数点不能出现两次
                if (hasE || decimal) return false;
                decimal = true;
            } else if (str[i] < '0' || str[i] > '9') // 不合法字符
                return false;
        }
        return true;
    }
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容