leetcode 简单题(部分)

简单题需要get的点:
0、通识技巧:
A、每次循环都只进行一次操作,要么是删除,要么是赋值;
B、每次判断一个结点的值的时候,先判断该结点是否存在;

     // 删除一个链表中的指定的值的结点。
     ListNode* removeElements(ListNode* head, int val) {
           // 最难的是判断:为空和为1的情况
           if(!head) return head;
           while(head&&head->val==val) head=head->next;   // 把头节点中需要删除的结点给去掉
           ListNode* begin = head;
           while(head){
                if(head->next&&head->next->val==val) head->next=head->next->next;  
                else head = head->next;
           }
           return begin;
      }

C、任何逻辑,都有因果关系,所以在进行逻辑判断的时候,一定是根据某个逻辑来进行改变


1、字符串类:
A、【字符型可以看成是数字型,一样可以用来 "异或";最开始指向NULL即可;(我不知道这样写好不好,如果不好,就把tmp初始化为字符串第一个字符)】

       char findTheDifference(string s, string t) {
            char tmp=NULL;      // 可以初始化字符串的第一个字母
            for(auto c:s) tmp=tmp^c;
            for(auto c:t) tmp=tmp^c;
            return tmp;
        }

B、【字符串相关的一个很好的数据结构是 字符数组,通过用字符的相对位置进行字符压缩!这个方法在这里可能不是唯一的,而是可以用标准的unordered_map来进行统计】
给一个字符串,找到在字符串中第一个没有重复出现的字符,并返回它的下标,如果不存在,就返回-1;
(这里可以用 record,也可以 用 unordered_map 来做,因为只是做个统计,然后再遍历一遍字符串,找出那个统计次数为1的值)
(该题目做两个字符串的异序判断也是很好用的,比一个unordered_map效率都高很多)

int firstUniqChar(string s) {
     vector<int> record(26);
     for(auto c:s){
            record[c-'a']++;
     }
     for(int i=0;i<s.size();i++){
            if(record[s[i]-'a']==1) return i;
     }
     return -1;
       }

C:字符串模拟数字操作--二进制数相加:
tip:这里有几个很重要的点:
1)因为是字符串模拟数字,所以每一个单独的字符转化到数字的时候用-'0'的方式完成;同理,在给结果串赋值的时候,也需要加上'0':

class Solution {
public:
    string addBinary(string a, string b) {
        // 将两个字符串进行逆转
        reverse(a.begin(),a.end());
        reverse(b.begin(),b.end());
        // 设置进位符和总长度和结果串
        int flag = 0;
        int lenth = 0;
        string res = "";
        if(a.size()>b.size()){
            lenth = a.size();
            res = a; 
        }else{
            lenth = b.size();
            res = b;             
        }
        // 对字符串中每一个字符逐次进行相加比较
        for(int i=0;i<lenth;i++){
            int int_a = i<a.size()?a[i]-'0':0;
            int int_b = i<b.size()?b[i]-'0':0;
            if((int_a+int_b+flag)>1){
                if(int_a+int_b+flag==2) res[i]='0';
                if(int_a+int_b+flag==3) res[i]='1';
                flag=1;
            }else{
                res[i]=int_a+int_b+flag+'0';  
                flag=0;
            } 
        }
        if(flag==1) res=res+"1";
        reverse(res.begin(),res.end());
        return res;
    }
};

2、数值类(逻辑题和选择题都有可能出):
A:有些 x%4==0 的计算可以转换为位的运算:
x&3==0(需要注意的是,单目运算符的优先级很低,所以需要加括号),总的而言,效率还是提高了很多。(Nim game)

B:与数值运算很相关的一系列操作:

     (1)int tmp = num & (~num+1)   // 找到 num 中最右边的那个1所对应的数值:例如:num: 11000;tmp: 1000 
     (2)int tmp = num - (~num+1)    //  消掉 num 中最右边的那个1后所对应的数值:例如:num: 11000;tmp: 10000

C:给出n!,然后算出n!的结果中有多少个0,这个题不仅是在逻辑题中出现过,在编程题中也出现过:
(一个阶乘里面 2肯定比5多, 所以只要5,一定能配成10;关键在于有几个5)

      int trailingZeroes(int n) {
           int res=0;
           while(n>0){
               res+=n/5;
               n=n/5;
           }
           return res;
      }

比如125!由下面的部分组成:(1+2+3+4+5+......+25) * 5
除去5之后,为25,25又由下面的部分组成:(1+2+3+4+5) * 5
除去5之后,为5,5又由下面的部分组成:1 * 5
所以最后:25 + 5 +1 =31

D:toupper() 转换为大写;tolower() 转换为小写;
E:素数,这种题虽然没有在任何一个平台上写过,但是我依然认为是很重要的:
这里需要多了解些素数的性质:
1)素数除了2以外,永远是奇数,所以只需要删掉奇数中为合数的部分。所以统计的时候是从3开始;
2)对于每一个符合素数的值t外,t*3,t*5,t*7,t*9......都是合数。
3)但是对于t而言,t*(3,5....t) 之前在 t=3,t=5,t=7 的时候,以及判断过了,所以,直接从 t*t 开始。

class Solution {
public:
    int countPrimes(int n) {
        if(n<3) return 0;
        // 2是素数中唯一的偶数,而其他的数都是奇数.
        // 如果i=3,那么 3*3, 3*(3+2), 3*(3+4)......
        // 如果i=5,那么 5*5, 5*(5+2), 5*(5+4)......【注意,5*3已经被】
        // 而素数的基本判断方法是除了自己和1以外,不能被任何数整除。
        // 感觉这也是一个动态规划统计过程。
        vector<int> vec(n,0);
        for(int i=3;i*i<n;i=i+2){
            if(vec[i]==0){
                for(int j=i*i;j<n;j=j+2*i){
                    vec[j]=1;
                }
            }
        }
        int res=1;
        for(int i=3;i<n;i=i+2){
            if(vec[i]==0) res++;
        }
        return res;
    }
};

F:数字和数字型字符串
这个轮子在很多地方都出现过,特别在一些比较复杂的题型里面:

Reverse Integer:
(一个正常的数字只需要不断通过%10 和 /10 来得到所有的数,而替换的数只需要*10+i)
    int reverse(int x) {
        long left=0; //用long 的好处在于,不怕真的越界了
        int right = x;
        while(right){
            left = left*10 + right%10;
            right= right/10;
        }
        if(left>0) return left>INT_MAX?0:left; 
        else if(left<0) return left<INT_MIN?0:left; 
        else return 0;
    }

3、二叉树相关:
A:在写深搜的时候,原函数不动,而是将其他函数作为主要的递归函数,并把中间状态值传进去。直到最后的临界条件下,进行判断。(根结点的判断方式:左&右两个子结点为空)

    int res;
    void help(TreeNode* root, int count){
 // 这里是找最大,如果是找最小,那么就需要直接剪枝,将大于全局最小值的数进行剪枝。
        if(!root->left&&!root->right){
            res = count>res?count:res;  
        } 
        if(root->left) help(root->left,count+1);
        if(root->right) help(root->right,count+1);
    }
    int maxDepth(TreeNode* root) {
        if(!root) return 0; // 对于指针,需要先判断是否为空。
        res=0;
        help(root,1);
        return res;
    }

B:平衡二叉树(AVL):首先,平衡二叉树的定义就是左右两个子树的高度相差不超过1;如何判断是否是平衡二叉树,其实只要两个子树是平衡的,那以我为根节点的子树就是平衡的。

虽然是做判断树的平衡性,但是肯定还是深搜,而用树的高度作为返回值是合适的,如果返回值是正数,说明了两点:A:树高 ; B:该树是平衡的;如果返回值是负数,就不用说了,肯定是不平衡的,只要有一个小子树是不平衡的,那么整棵树都不是平衡的,基于此,写出下面的迭代算法:

写这种题目的时候,入口做的事情不能太多,只是做一个准备工作,比如,赋初值,比如设置迭代的状态变量,最后根据迭代的状态变量进行判断。

基本上可以这么想:叶子结点和非叶子结点,非叶子结点有两种可能:有左右子节点;只有左或右结点!
也就是说,要保证,每一步做了后,都可以判断,并影响最终的效率。

class Solution {
public:
    int help(TreeNode* root){
        int a=0,b=0;
        if(!root->left&&!root->right) return 1;  // 最好的方式是不需要深搜了,直接判断!
        if(root->left) a=help(root->left);  // 就算是暴利剪枝,也需要分别判断,在处理大数据集合的时候效果会好很多。
        if(a==-1) return -1;
        if(root->right) b=help(root->right); 
        if(b==-1) return -1;
        else if(abs(a-b)<=1) return max(a,b)+1; // 对深搜的结果进行返回,如果是动规的话,需要在这个地方对矩阵中
        else return -1;
    }

    bool isBalanced(TreeNode* root) {
        if(!root) return true;
        if(help(root)!=-1) return true;
        else return false;
    }
};

4、数组类:
A:有道题很有意思,找出两个数组中交集的那部分的数字:时间:O(n) 空间:O(n)

关于 unordered_map 相关的:unordered_map<int,pair<int,int>> record;
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        vector<int> res;
        if(nums1.size()==0||nums2.size()==0) return res;
        unordered_map<int ,int> vec;
        for(auto s:nums1) vec[s]++;
        for(auto s:nums2)       // 如果有库存的话,就直接放进入了。
if(vec[s]>=1){
res.push_back(s);
vec[s]--;
}
        return res;
    }
};

这里其实还有些需要注意的是,如果其中有一个的长度为0,那么就肯定没有交集了。

B:Sum系列
1) two_sum:两个数的和
在一个无序的数组里找到满足 target 的两个数的和:

最方便的方法是先排序(nlogn),然后再两边夹逼来找到合适的数字(O(n)),但是总的时间复杂度为O(nlogn);
而效率上最快的方法应该还是基于统计的,用unordered_map<int,int> 进行统计,因为查找效率为O(1),所以每个元素最多遍历2遍,时间复杂度为O(n)

如果在已经排序的情况下:

      vector<int> twoSum(vector<int>& numbers, int target) {
          int left=0, right=numbers.size()-1;
          while(left<right){
              int rest = target - numbers[left];
              while(numbers[right]>rest) right--;
              if(numbers[right]==rest) return vector<int>{left+1,right+1};
              else left++;
          }
          return vector<int>();
      }

C:从一个已排序的数组中原地移除重复的元素

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.size()==0) return 0;
        // 用标记法将合适的数据放在合适的位置,然后返回合理的长度,最后,erase掉多余的数据
        int left=0;     // 标记应该放入元素的地方
        int i=0;
        for(;i<nums.size()-1;i++){
            while(i<nums.size()-1&&nums[i]==nums[i+1]) i++; 
            nums[left] = nums[i];
            left++;   
        }
        if(i==(nums.size()-1)) nums[left++] = nums[i];      // 将最后一个数放进去。
        nums.erase(nums.begin()+left,nums.end());
        return left;
    }
};

D:模式匹配类:

Given a pattern and a string str, find if str follows the same pattern.
Examples:
pattern = "abba", str = "dog cat cat dog" should return true.
pattern = "abba", str = "dog cat cat fish" should return false.
pattern = "aaaa", str = "dog cat cat dog" should return false.
pattern = "abba", str = "dog dog dog dog" should return false.

用空格间隔的字符串,拆分代码:

vector<string> vec;
string tmp="";
stringstream isstream(str);
while(isstream >> tmp) strvec.push_back(tmp);

注意:unordered_map 的变量是可以用 find 去进行查询的,当查询不到,是返回end(),同理,当查询到了,应该是返回对应的数值的迭代器。

class Solution {
public:
    bool wordPattern(string pattern, string str) {
        unordered_map<char,string> rec;
        unordered_map<string,char> rec2;
        // 拆分字符串
        vector<string> record;
        string tmp="";
        stringstream isstream(str);
        while(isstream >> tmp) record.push_back(tmp);
        // 模式匹配
        if(pattern.size()!=record.size()) return false;
        for(int i=0;i<pattern.size();i++){
            if(rec[pattern[i]]==""){
                if(rec2[record[i]]==NULL){
                    rec[pattern[i]]=record[i];
                    rec2[record[i]]=pattern[i];
                }else return false;
            }
            else{
                if(rec[pattern[i]]!=record[i]||rec2[record[i]]!=pattern[i]) return false;
            }
        }
        return true;
    }
};

E:给定数组的轴,然后按照这个轴进行旋转:
(这个题目变相地考过,这里可以是字符串,也可以是数组)
Rotate Array 这里有意思的是,这里
举例说明:[1,2,3,4,5,6,7] ,轴是3
首先,reverse 整个数组,变为:[7,6,5,4,3,2,1] 然后,reverse 前三个,再reverse 后四个

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        k%=nums.size();
        reverse(nums.begin(),nums.end());
        reverse(nums.begin(),nums.begin()+k);
        reverse(nums.begin()+k,nums.end());
    }
};

5、链表类(简单题一般都会出手写代码题):
A:链表逆转的标准:判断首节点是否为空,然后判断:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(!head) return nullptr;
        ListNode* prev=nullptr; ListNode* next = nullptr;
        while(head!=nullptr){
            next = head->next;
            head->next= prev;
            prev = head;
            head = next;
        }
        return prev;
    }
};

B:合并两个链表:(合并两个排序的链表成一个排序的链表)用一个新的指针来穿针引线:

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
  // 新的指针
        ListNode* head = new ListNode(0);
        ListNode* tmp = head;
//  对两个指针链所共有的部分进行判断
        while(l1&&l2){
            if(l1->val<=l2->val){
                tmp->next = l1;
                l1=l1->next;
            }else{
                tmp->next = l2;
                l2=l2->next;
            }
            tmp=tmp->next;
        }
        if(l1 == nullptr) tmp->next = l2;
        else if(l2 == nullptr) tmp->next = l1;
        return head->next;
    }
};

C:链表操作之每一对链表结点相互交换:
(如果只是改变结点的值,那种不叫交换,应该是交换两个结点,只要涉及到链表的拆分,而且与前一个结点和后一个结点相关的话,就可以统一用下面的初始化:

   ListNode* next = nullptr;
   ListNode* prev = new ListNode(0);
   ListNode* res = prev;
---------------------------------------
    ListNode* swapPairs(ListNode* head) {
        ListNode* next = nullptr;
        ListNode* prev = new ListNode(0);
        ListNode* res = prev;
        while(head){
            if(head->next){
                next = head->next->next;
                prev->next =head->next;
                head->next->next = head;
                head->next = next;
                prev = head;
                head = next; 
            }else{
                if(!res->next) res->next = head;
                head = head->next;
            }
        }
        return res->next;
    }

D:先后指针:移除倒数第N个结点:
首先用一个指针,先走N步,然后,再用另一个指针指向头结点,两个指针同时走,后面的那个指针将会指向需要删除的那个结点的前一个结点。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        if(!head) return NULL;
        ListNode* before=head;
        ListNode* begin=head;
        while(n>0){
            before=before->next;
            n--;
        }
        while(before&&before->next){
            before= before->next;
            begin= begin->next;
        }
 // 通过对 before 的一个判断,来决定具体是删除当前结点,还是当前结点的下一个结点。
        if(!before){ // 如果 before为 nullptr, 那么说明要删除的是第一个节点
            ListNode* tmp = head;
            head=head->next;
            delete tmp;
        }else if(!before->next){ // 如果 before->next为 nullptr, 那么说明要删除的是后一个节点
            ListNode* tmp = begin->next;
            begin->next = begin->next->next;
            delete tmp;
        }
        return head;
    }
};

E:两个链表有交集,求交集的起点:
(最怕的是上下代码有黏带,最好的方式是每一次循环给变量赋一次值)

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(!headA||!headB) return NULL;
        ListNode * head1 = headA;
        ListNode * head2 = headB;
        while(head1!=head2){
            if(head1==NULL) head1 = headB;
            else head1=head1->next;
            if(head2==NULL) head2 = headA;
            else head2=head2->next;
        }
        return head1;
    }
};

F:链表回文:
几个重要的轮子:
1)快慢指针
// 快指针的跳转分两种 A:落在最后一个真正的节点上;B:落在最后一个真正的节点的后面那个NULL上

        while(node1&&node1->next){
            node1=node1->next->next;
            node2=node2->next;
        }
        ListNode* mid=node2;
        if(node1) node2= node2->next;

2)链表逆转
// 找到了mid就是链表中间的指针,那么就有了中点了。

        node1 = head;
        ListNode* prev=NULL;
        ListNode* next=NULL;
        while(node1!=mid){
            next = node1->next;
            node1->next=prev;
            prev =node1;
            node1=next;
        }

当然,这两步可以合起来!
// 快慢指针+链表逆转

        ListNode* fast= head;
        ListNode* slow= head;
        ListNode* before =nullptr,*next=nullptr;
        //链表的逆转
        while(fast!=nullptr&&fast->next!=nullptr){
            fast=fast->next->next;
            next=slow->next;
            slow->next=before;
            before =slow;
            slow=next;
        }

G:一些小的建议:每次调一个指针的val之前先判断该指针是否存在:

   ListNode* removeElements(ListNode* head, int val) {
        if(!head) return head;
        while(head&&head->val==val) head=head->next;
        ListNode* begin = head;
        while(head){
            if(head->next&&head->next->val==val) head->next=head->next->next;  
            else head = head->next;
        }
        return begin;
    }

7、pow of index系列,就是给一个整数,来判断是否该数是 index 的指数,不准用循环或者递归:
首先,循环的方法是(对 index 取余,然后再除以 index 然后再取余)

bool isPowerOfThree(int n) {
    if(n<=0) return false;
    while(n>1){
         if(n%3==0) n=n/3;
         else return false;
    }
    return true;
}

非循环的方法是:(找到系统支持的范围内3的指数最大的值,然后判断它是否可以整除n,这个对于3的指数的求法是比较好的)

bool isPowerOfThree(int n) {
    if (n<=0) return false;
    int t = pow(3 , (int)( log(INT_MAX)/log(3)) );
    return (t%n == 0); 
}

特殊的,对于判断是否是2的指数的方法(因为2的倍数,也就意味着整个数的二进制位只有一个为1,所以通过 return !n&(n-1) ; 就可以判断出来)
再特殊一点,对于判断是否是4的指数的方法(首先对于2也好,4也好,都必须是只有1个1;所以,如果有两个1的数肯定是错的,然后再判断和0xaaaaaaaa相与的结果,如果为0则是真,为0xaaaaaaaa则为假。

bool isPowerOfFour(int num){
   if(num<=0) return false;
   int tmp = num&(~num+1);    //    找出最右边的一个1,并判断是否只有一个1;
   if( tmp!=num ) return false;
   else if( tmp&0xaaaaaaaa ) return false;
   return true;
}

8、概念定义的一些题:

Ugly Number :一组正数,这组正数的质因子只包括 所指定的一些数字,比如 easy 题中的 2,3,5. 而1往往被认为是 Ugly Number,简单地处理方式是不断 while 循环去除以对应质数。

9、拟快排系列:

A:拟快排版本1:在字符串中,将元音字母的顺序进行逆转,方法就是从字符串的左右都分别找到需要进行对换的字母,然后进行交换;

      string reverseVowels(string s) {
        if(s=="") return s;
        int left=0,right=s.size()-1;
        char left_c=tolower(s[left]), right_c=tolower(s[right]);
        while(left<right){
            while(left_c!='a'&&left_c!='e'&&left_c!='i'&&left_c!='o'&&left_c!='u'){
                ++left;
                left_c=tolower(s[left]);
            }
            while(right_c!='a'&&right_c!='e'&&right_c!='i'&&right_c!='o'&&right_c!='u'){
                --right;
                right_c=tolower(s[right]);
            }
            if(left<right) swap(s[left],s[right]);
            ++left;
            left_c=tolower(s[left]);
            --right;
            right_c=tolower(s[right]);
        }
        return s;
    }

10、回文系列:

A:一个整数是否是回文的,原地判断:(整数回文相对比较复杂)
(对于数据中,所谓的一半的位置是很难真正找到的,既然这样,就需要用到递归的方法去找)
一般与数值有关的数字操作,包括>>、<<、&、|、/、%

class Solution {
public:
    bool isPd(int xn, int &xd) {
        if(xn / 10 == 0){   
    if((xd % 10) == xn){
            xd = xd/10;
            return true;
       }
       return false;
    }else{
            bool sign = isPd(xn/10, xd);
            if(sign && (xn % 10) == (xd%10) ){
                xd = xd/10;
                return true;
            } 
            return  false;
        }
    }
    bool isPalindrome(int x) {
        if(x < 0) return false;
        return isPd(x,x);
    }
};

B:一个链表是否是回文的,原地判断
(这个问题的解决方法是,快慢指针找到链表的中点,然后又回到起点将起点到中点这一段的链表反转,反转之后,再双向逐个比较,如果有任何一个不相同,则返回否)

C:字符串回文,含其他的多余字符,需要过滤掉其他的多余字符来进行回文比较:

    bool isPalindrome(string s) {
        // 字符串的回文理论上比较简单,但是加了很多的其他的符号,关键步骤在于左右夹逼的时候,如果遇到非字母数字的字母情况下,需要跳过,终点在于两个下标在一起。
        string res="";
        for(int i=0,j=s.size()-1;i<j;i++,j--){
            char first_letter,second_letter;
            while(!((s[i]-'a'<26 && s[i]-'a'>=0)||(s[i]-'A'<26 && s[i]-'A'>=0)||(s[i]-'0'<=9 && s[i]-'0'>=0))) i++; 
            if(i<=j) first_letter = tolower(s[i]);
            while(!((s[j]-'a'<26 && s[j]-'a'>=0)||(s[j]-'A'<26 && s[j]-'A'>=0)||(s[j]-'0'<=9 && s[j]-'0'>=0))) j--;
            if(i<=j) second_letter = tolower(s[j]);
            if(first_letter != second_letter) return false;
        }
        return true;
    }
    tip: ::isalnum 可以用来比较一个字母是不是数字和字母

11、智力题类:

A:数独:

clipboard.png
class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        int size = board.size();
        for(int i=0;i<size;i++)
            for(int j=0;j<size;j++){
                if(board[i][j]=='.') continue;// 能不递归就不递归
                int count=0;
                // 判断行和列是否有冲突
                for(int k=0;k<size;k++){
                    if(board[i][k]==board[i][j]) count++;  
                    if(board[k][j]==board[i][j]) count++;
                    if(count>2) return false;
                } 
                // 判断九宫格是否有冲突
                for(int l=(i/3)*3;l<(i/3)*3+3;l++)
                    for(int m=(j/3)*3;m<(j/3)*3+3;m++)
                        if(board[l][m]==board[i][j]) count++;
                if(count>3) return false;
            }
        return true;
    }
};

12、几何数学题

几何数学题需要找到合适切入角度。

13、重构题
A:Min Stack [加红的原因是,网易游戏问过]

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
push(x) -- Push element x onto stack.
pop() -- Removes the element on top of the stack.
top() -- Get the top element.
getMin() -- Retrieve the minimum element in the stack.

这个题简单的原因在于两个stack就可以完成,push 和 pop 用来维护第二个 stack,第二个 stack 是记录最小值的。当 Push 一个数值的时候,如果比上一个数小,那么把该数放进去,如果大于,则把第二个stack的top值放进来。

14、场景题
(将算法放在一个应用场景中,然后去解决,比如之前的LRU!再比如twitte设计)、
A:First Bad Version
说得很复杂,其实也就是找到一维数组中的连续坏点的起点。因为这里只有good or bad,所以,不存在乱序的问题,最好的办法是二分查找。

class Solution {
public:
    int firstBadVersion(int n) {
        int left=1;
        int right = n;
        while(left<right){
            int mid = left+(right-left)/2;
            if(isBadVersion(mid)) right =mid;  // 这里是mid,而不是mid-1
            else left =mid+1;
        }
        return left;
    }
};

其实,二分查找有时候会因为把握不了边界而出错,但是,需要知道的是,每一次二分的时候,要尽量将正确的答案留下来。

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

推荐阅读更多精彩内容