股票買賣系列問題的動態(tài)規(guī)劃分析與求解

刷股票問題看到的一個大神解答之碗,搬運過來呛凶,給大家分享。


作者:labuladong
鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/
來源:力扣(LeetCode)
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)弹谁,非商業(yè)轉(zhuǎn)載請注明出處。

下面是正文:


很多讀者抱怨股票系列問題奇技淫巧太多句喜,如果面試真的遇到這類問題预愤,基本不會想到那些巧妙的辦法,怎么辦咳胃?所以本文拒絕奇技淫巧植康,而是穩(wěn)扎穩(wěn)打,只用一種通用方法解決所用問題展懈,以不變應萬變销睁。

這篇文章用狀態(tài)機的技巧來解決供璧,可以全部提交通過。不要覺得這個名詞高大上冻记,文學詞匯而已睡毒,實際上就是 DP table,看一眼就明白了冗栗。

先隨便抽出一道題演顾,看看別人的解法:

int maxProfit(vector<int>& prices) {
    if(prices.empty()) return 0;
    int s1=-prices[0],s2=INT_MIN,s3=INT_MIN,s4=INT_MIN;
        
    for(int i=1;i<prices.size();++i) {            
        s1 = max(s1, -prices[i]);
        s2 = max(s2, s1+prices[i]);
        s3 = max(s3, s2-prices[i]);
        s4 = max(s4, s3+prices[i]);
    }
    return max(0,s4);
}

能看懂吧?會做了嗎隅居?不可能的钠至,你看不懂,這才正常胎源。就算你勉強看懂了棉钧,下一個問題你還是做不出來。為什么別人能寫出這么詭異卻又高效的解法呢乒融?因為這類問題是有框架的掰盘,但是人家不會告訴你的,因為一旦告訴你赞季,你五分鐘就學會了愧捕,該算法題就不再神秘,變得不堪一擊了申钩。

本文就來告訴你這個框架次绘,然后帶著你一道一道秒殺。

這 6 道股票買賣問題是有共性的撒遣,我們通過對第四題(限制最大交易次數(shù)為 k)的分析一道一道解決邮偎。因為第四題是一個最泛化的形式,其他的問題都是這個形式的簡化义黎。

第一題是只進行一次交易禾进,相當于 k = 1;第二題是不限交易次數(shù)廉涕,相當于 k = +infinity(正無窮)泻云;第三題是只進行 2 次交易,相當于 k = 2狐蜕;剩下兩道也是不限次數(shù)宠纯,但是加了交易「冷凍期」和「手續(xù)費」的額外條件,其實就是第二題的變種层释,都很容易處理婆瓜。

一、窮舉框架

首先贡羔,還是一樣的思路:如何窮舉廉白?這里的窮舉思路和上篇文章遞歸的思想不太一樣个初。

遞歸其實是符合我們思考的邏輯的,一步步推進蒙秒,遇到無法解決的就丟給遞歸勃黍,一不小心就做出來了,可讀性還很好晕讲。缺點就是一旦出錯,你也不容易找到錯誤出現(xiàn)的原因马澈。比如上篇文章的遞歸解法瓢省,肯定還有計算冗余,但確實不容易找到痊班。

而這里勤婚,我們不用遞歸思想進行窮舉,而是利用「狀態(tài)」進行窮舉涤伐。我們具體到每一天馒胆,看看總共有幾種可能的「狀態(tài)」,再找出每個「狀態(tài)」對應的「選擇」凝果。我們要窮舉所有「狀態(tài)」祝迂,窮舉的目的是根據(jù)對應的「選擇」更新狀態(tài)。聽起來抽象器净,你只要記住「狀態(tài)」和「選擇」兩個詞就行型雳,下面實操一下就很容易明白了。

for 狀態(tài)1 in 狀態(tài)1的所有取值:
    for 狀態(tài)2 in 狀態(tài)2的所有取值:
        for ...
            dp[狀態(tài)1][狀態(tài)2][...] = 擇優(yōu)(選擇1山害,選擇2...)

比如說這個問題纠俭,每天都有三種「選擇」:買入、賣出浪慌、無操作冤荆,我們用 buy, sell, rest 表示這三種選擇。但問題是权纤,并不是每天都可以任意選擇這三種選擇的钓简,因為 sell 必須在 buy 之后,buy 必須在 sell 之后妖碉。那么 rest 操作還應該分兩種狀態(tài)涌庭,一種是 buy 之后的 rest(持有了股票),一種是 sell 之后的 rest(沒有持有股票)欧宜。而且別忘了坐榆,我們還有交易次數(shù) k 的限制,就是說你 buy 還只能在 k > 0 的前提下操作冗茸。

很復雜對吧席镀,不要怕匹中,我們現(xiàn)在的目的只是窮舉,你有再多的狀態(tài)豪诲,老夫要做的就是一把梭全部列舉出來顶捷。這個問題的「狀態(tài)」有三個,第一個是天數(shù)屎篱,第二個是允許交易的最大次數(shù)服赎,第三個是當前的持有狀態(tài)(即之前說的 rest 的狀態(tài),我們不妨用 1 表示持有交播,0 表示沒有持有)重虑。然后我們用一個三維數(shù)組就可以裝下這幾種狀態(tài)的全部組合:

dp[i][k][0 or 1]
0 <= i <= n-1, 1 <= k <= K
n 為天數(shù),大 K 為最多交易數(shù)
此問題共 n × K × 2 種狀態(tài)秦士,全部窮舉就能搞定缺厉。

for 0 <= i < n:
    for 1 <= k <= K:
        for s in {0, 1}:
            dp[i][k][s] = max(buy, sell, rest)

而且我們可以用自然語言描述出每一個狀態(tài)的含義,比如說 dp[3][2][1] 的含義就是:今天是第三天隧土,我現(xiàn)在手上持有著股票提针,至今最多進行 2 次交易。再比如 dp[2][3][0] 的含義:今天是第二天曹傀,我現(xiàn)在手上沒有持有股票辐脖,至今最多進行 3 次交易。很容易理解卖毁,對吧揖曾?

我們想求的最終答案是 dp[n - 1][K][0],即最后一天亥啦,最多允許 K 次交易炭剪,最多獲得多少利潤。讀者可能問為什么不是 dp[n - 1][K][1]翔脱?因為 [1] 代表手上還持有股票奴拦,[0] 表示手上的股票已經(jīng)賣出去了,很顯然后者得到的利潤一定大于前者届吁。

記住如何解釋「狀態(tài)」错妖,一旦你覺得哪里不好理解,把它翻譯成自然語言就容易理解了疚沐。

二暂氯、狀態(tài)轉(zhuǎn)移框架

現(xiàn)在,我們完成了「狀態(tài)」的窮舉亮蛔,我們開始思考每種「狀態(tài)」有哪些「選擇」痴施,應該如何更新「狀態(tài)」。只看「持有狀態(tài)」,可以畫個狀態(tài)轉(zhuǎn)移圖辣吃。


狀態(tài)轉(zhuǎn)移圖

通過這個圖可以很清楚地看到动遭,每種狀態(tài)(0 和 1)是如何轉(zhuǎn)移而來的。根據(jù)這個圖神得,我們來寫一下狀態(tài)轉(zhuǎn)移方程:

dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
              max(   選擇 rest  ,           選擇 sell      )

解釋:今天我沒有持有股票厘惦,有兩種可能:
要么是我昨天就沒有持有,然后今天選擇 rest哩簿,所以我今天還是沒有持有宵蕉;
要么是我昨天持有股票,但是今天我 sell 了节榜,所以我今天沒有持有股票了国裳。

dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
              max(   選擇 rest  ,           選擇 buy         )

解釋:今天我持有著股票,有兩種可能:
要么我昨天就持有著股票全跨,然后今天選擇 rest,所以我今天還持有著股票亿遂;
要么我昨天本沒有持有浓若,但今天我選擇 buy,所以今天我就持有股票了蛇数。

這個解釋應該很清楚了挪钓,如果 buy,就要從利潤中減去 prices[i]耳舅,如果 sell碌上,就要給利潤增加 prices[i]。今天的最大利潤就是這兩種可能選擇中較大的那個浦徊。而且注意 k 的限制馏予,我們在選擇 buy 的時候,把 k 減小了 1盔性,很好理解吧霞丧,當然你也可以在 sell 的時候減 1,一樣的冕香。

現(xiàn)在蛹尝,我們已經(jīng)完成了動態(tài)規(guī)劃中最困難的一步:狀態(tài)轉(zhuǎn)移方程。如果之前的內(nèi)容你都可以理解悉尾,那么你已經(jīng)可以秒殺所有問題了突那,只要套這個框架就行了。不過還差最后一點點构眯,就是定義 base case愕难,即最簡單的情況。

dp[-1][k][0] = 0
解釋:因為 i 是從 0 開始的,所以 i = -1 意味著還沒有開始务漩,這時候的利潤當然是 0 拄衰。
dp[-1][k][1] = -infinity
解釋:還沒開始的時候,是不可能持有股票的饵骨,用負無窮表示這種不可能翘悉。
dp[i][0][0] = 0
解釋:因為 k 是從 1 開始的,所以 k = 0 意味著根本不允許交易居触,這時候利潤當然是 0 妖混。
dp[i][0][1] = -infinity
解釋:不允許交易的情況下,是不可能持有股票的轮洋,用負無窮表示這種不可能制市。

把上面的狀態(tài)轉(zhuǎn)移方程總結(jié)一下:

base case:
dp[-1][k][0] = dp[i][0][0] = 0
dp[-1][k][1] = dp[i][0][1] = -infinity

狀態(tài)轉(zhuǎn)移方程:
dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])

讀者可能會問,這個數(shù)組索引是 -1 怎么編程表示出來呢弊予,負無窮怎么表示呢祥楣?這都是細節(jié)問題,有很多方法實現(xiàn)『浩猓現(xiàn)在完整的框架已經(jīng)完成误褪,下面開始具體化。

三碾褂、秒殺題目

第一題兽间,k = 1

直接套狀態(tài)轉(zhuǎn)移方程,根據(jù) base case正塌,可以做一些化簡:

dp[i][1][0] = max(dp[i-1][1][0], dp[i-1][1][1] + prices[i])
dp[i][1][1] = max(dp[i-1][1][1], dp[i-1][0][0] - prices[i]) 
            = max(dp[i-1][1][1], -prices[i])
解釋:k = 0 的 base case嘀略,所以 dp[i-1][0][0] = 0。

現(xiàn)在發(fā)現(xiàn) k 都是 1乓诽,不會改變帜羊,即 k 對狀態(tài)轉(zhuǎn)移已經(jīng)沒有影響了。
可以進行進一步化簡去掉所有 k:
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], -prices[i])

直接寫出代碼:

int n = prices.length;
int[][] dp = new int[n][2];
for (int i = 0; i < n; i++) {
    dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
    dp[i][1] = Math.max(dp[i-1][1], -prices[i]);
}
return dp[n - 1][0];

顯然 i = 0 時 dp[i-1] 是不合法的问裕。這是因為我們沒有對 i 的 base case 進行處理逮壁。可以這樣處理:

for (int i = 0; i < n; i++) {
    if (i - 1 == -1) {
        dp[i][0] = 0;
        // 解釋:
        //   dp[i][0] 
        // = max(dp[-1][0], dp[-1][1] + prices[i])
        // = max(0, -infinity + prices[i]) = 0
        dp[i][1] = -prices[i];
        //解釋:
        //   dp[i][1] 
        // = max(dp[-1][1], dp[-1][0] - prices[i])
        // = max(-infinity, 0 - prices[i]) 
        // = -prices[i]
        continue;
    }
    dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
    dp[i][1] = Math.max(dp[i-1][1], -prices[i]);
}
return dp[n - 1][0];

第一題就解決了粮宛,但是這樣處理 base case 很麻煩窥淆,而且注意一下狀態(tài)轉(zhuǎn)移方程,新狀態(tài)只和相鄰的一個狀態(tài)有關巍杈,其實不用整個 dp 數(shù)組忧饭,只需要一個變量儲存相鄰的那個狀態(tài)就足夠了,這樣可以把空間復雜度降到 O(1):

// k == 1
int maxProfit_k_1(int[] prices) {
    int n = prices.length;
    // base case: dp[-1][0] = 0, dp[-1][1] = -infinity
    int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
    for (int i = 0; i < n; i++) {
        // dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
        dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
        // dp[i][1] = max(dp[i-1][1], -prices[i])
        dp_i_1 = Math.max(dp_i_1, -prices[i]);
    }
    return dp_i_0;
}

兩種方式都是一樣的筷畦,不過這種編程方法簡潔很多词裤。但是如果沒有前面狀態(tài)轉(zhuǎn)移方程的引導刺洒,是肯定看不懂的。后續(xù)的題目吼砂,我主要寫這種空間復雜度 O(1) 的解法逆航。

第二題,k = +infinity

如果 k 為正無窮渔肩,那么就可以認為 k 和 k - 1 是一樣的因俐。可以這樣改寫框架:

dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
            = max(dp[i-1][k][1], dp[i-1][k][0] - prices[i])

我們發(fā)現(xiàn)數(shù)組中的 k 已經(jīng)不會改變了周偎,也就是說不需要記錄 k 這個狀態(tài)了:
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])

直接翻譯成代碼:

int maxProfit_k_inf(int[] prices) {
    int n = prices.length;
    int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
    for (int i = 0; i < n; i++) {
        int temp = dp_i_0;
        dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
        dp_i_1 = Math.max(dp_i_1, temp - prices[i]);
    }
    return dp_i_0;
}

第三題抹剩,k = +infinity with cooldown

每次 sell 之后要等一天才能繼續(xù)交易。只要把這個特點融入上一題的狀態(tài)轉(zhuǎn)移方程即可:

dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-2][0] - prices[i])
解釋:第 i 天選擇 buy 的時候蓉坎,要從 i-2 的狀態(tài)轉(zhuǎn)移澳眷,而不是 i-1 。

翻譯成代碼:

int maxProfit_with_cool(int[] prices) {
    int n = prices.length;
    int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
    int dp_pre_0 = 0; // 代表 dp[i-2][0]
    for (int i = 0; i < n; i++) {
        int temp = dp_i_0;
        dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
        dp_i_1 = Math.max(dp_i_1, dp_pre_0 - prices[i]);
        dp_pre_0 = temp;
    }
    return dp_i_0;
}

第四題蛉艾,k = +infinity with fee

每次交易要支付手續(xù)費钳踊,只要把手續(xù)費從利潤中減去即可。改寫方程:

dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i] - fee)
解釋:相當于買入股票的價格升高了勿侯。

在第一個式子里減也是一樣的箍土,相當于賣出股票的價格減小了。
直接翻譯成代碼:

int maxProfit_with_fee(int[] prices, int fee) {
    int n = prices.length;
    int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
    for (int i = 0; i < n; i++) {
        int temp = dp_i_0;
        dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
        dp_i_1 = Math.max(dp_i_1, temp - prices[i] - fee);
    }
    return dp_i_0;
}

第五題罐监,k = 2

k = 2 和前面題目的情況稍微不同,因為上面的情況都和 k 的關系不太大瞒爬。要么 k 是正無窮弓柱,狀態(tài)轉(zhuǎn)移和 k 沒關系了;要么 k = 1侧但,跟 k = 0 這個 base case 挨得近矢空,最后也沒有存在感。

這道題 k = 2 和后面要講的 k 是任意正整數(shù)的情況中禀横,對 k 的處理就凸顯出來了屁药。我們直接寫代碼,邊寫邊分析原因柏锄。

原始的動態(tài)轉(zhuǎn)移方程酿箭,沒有可化簡的地方
dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])

按照之前的代碼,我們可能想當然這樣寫代碼(錯誤的):

int k = 2;
int[][][] dp = new int[n][k + 1][2];
for (int i = 0; i < n; i++)
    if (i - 1 == -1) { /* 處理一下 base case*/ }
    dp[i][k][0] = Math.max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);
    dp[i][k][1] = Math.max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);
}
return dp[n - 1][k][0];

為什么錯誤趾娃?我這不是照著狀態(tài)轉(zhuǎn)移方程寫的嗎缭嫡?

還記得前面總結(jié)的「窮舉框架」嗎?就是說我們必須窮舉所有狀態(tài)抬闷。其實我們之前的解法妇蛀,都在窮舉所有狀態(tài)耕突,只是之前的題目中 k 都被化簡掉了。這道題由于沒有消掉 k 的影響评架,所以必須要對 k 進行窮舉:

int max_k = 2;
int[][][] dp = new int[n][max_k + 1][2];
for (int i = 0; i < n; i++) {
    for (int k = max_k; k >= 1; k--) {
        if (i - 1 == -1) { 
            /* 處理 base case */
            dp[i][k][0] = 0;
            dp[i][k][1] = -prices[i];
            continue;
        }
        dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);
        dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);
    }
}
// 窮舉了 n × max_k × 2 個狀態(tài)眷茁,正確。
return dp[n - 1][max_k][0];

如果你不理解纵诞,可以返回第一點「窮舉框架」重新閱讀體會一下上祈。

這里 k 取值范圍比較小,所以可以不用 for 循環(huán)挣磨,直接把 k = 1 和 2 的情況手動列舉出來也可以:

dp[i][2][0] = max(dp[i-1][2][0], dp[i-1][2][1] + prices[i])
dp[i][2][1] = max(dp[i-1][2][1], dp[i-1][1][0] - prices[i])
dp[i][1][0] = max(dp[i-1][1][0], dp[i-1][1][1] + prices[i])
dp[i][1][1] = max(dp[i-1][1][1], -prices[i])

int maxProfit_k_2(int[] prices) {
    int dp_i10 = 0, dp_i11 = Integer.MIN_VALUE;
    int dp_i20 = 0, dp_i21 = Integer.MIN_VALUE;
    for (int price : prices) {
        dp_i20 = Math.max(dp_i20, dp_i21 + price);
        dp_i21 = Math.max(dp_i21, dp_i10 - price);
        dp_i10 = Math.max(dp_i10, dp_i11 + price);
        dp_i11 = Math.max(dp_i11, -price);
    }
    return dp_i20;
}

有狀態(tài)轉(zhuǎn)移方程和含義明確的變量名指導雇逞,相信你很容易看懂。其實我們可以故弄玄虛茁裙,把上述四個變量換成 a, b, c, d塘砸。這樣當別人看到你的代碼時就會一頭霧水,大驚失色晤锥,不得不對你肅然起敬掉蔬。

第六題,k = any integer

有了上一題 k = 2 的鋪墊矾瘾,這題應該和上一題的第一個解法沒啥區(qū)別女轿。但是出現(xiàn)了一個超內(nèi)存的錯誤,原來是傳入的 k 值會非常大壕翩,dp 數(shù)組太大了◎燃#現(xiàn)在想想,交易次數(shù) k 最多有多大呢放妈?

一次交易由買入和賣出構(gòu)成北救,至少需要兩天。所以說有效的限制 k 應該不超過 n/2芜抒,如果超過珍策,就沒有約束作用了,相當于 k = +infinity宅倒。這種情況是之前解決過的攘宙。

直接把之前的代碼重用:

int maxProfit_k_any(int max_k, int[] prices) {
    int n = prices.length;
    if (max_k > n / 2) 
        return maxProfit_k_inf(prices);

    int[][][] dp = new int[n][max_k + 1][2];
    for (int i = 0; i < n; i++) 
        for (int k = max_k; k >= 1; k--) {
            if (i - 1 == -1) { 
                /* 處理 base case */
                dp[i][k][0] = 0;
                dp[i][k][1] = -prices[i];
                continue;
            }
            dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);
            dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);     
        }
    return dp[n - 1][max_k][0];
}

至此,6 道題目通過一個狀態(tài)轉(zhuǎn)移方程全部解決拐迁。

四蹭劈、最后總結(jié)

本文給大家講了如何通過狀態(tài)轉(zhuǎn)移的方法解決復雜的問題,用一個狀態(tài)轉(zhuǎn)移方程秒殺了 6 道股票買賣問題线召,現(xiàn)在想想链方,其實也不算難對吧?這已經(jīng)屬于動態(tài)規(guī)劃問題中較困難的了灶搜。

關鍵就在于列舉出所有可能的「狀態(tài)」祟蚀,然后想想怎么窮舉更新這些「狀態(tài)」工窍。一般用一個多維 dp 數(shù)組儲存這些狀態(tài),從 base case 開始向后推進前酿,推進到最后的狀態(tài)患雏,就是我們想要的答案。想想這個過程罢维,你是不是有點理解「動態(tài)規(guī)劃」這個名詞的意義了呢淹仑?

具體到股票買賣問題,我們發(fā)現(xiàn)了三個狀態(tài)肺孵,使用了一個三維數(shù)組匀借,無非還是窮舉 + 更新,不過我們可以說的高大上一點平窘,這叫「三維 DP」吓肋,怕不怕?這個大實話一說瑰艘,立刻顯得你高人一等是鬼,名利雙收有沒有。

所以,大家不要被各種高大上的名詞嚇到,再多的困難問題盏浇,奇技淫巧,也不過是基本套路的不斷升級組合產(chǎn)生的攒发。只要把住算法的底層原理,即可舉一反三,逐個擊破。


我們沒能力發(fā)現(xiàn)知識紫皇,我們只是知識的寄生蟲

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市腋寨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌化焕,老刑警劉巖萄窜,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異撒桨,居然都是意外死亡查刻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門凤类,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穗泵,“玉大人,你說我怎么就攤上這事谜疤〉柩樱” “怎么了现诀?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長履肃。 經(jīng)常有香客問我仔沿,道長,這世上最難降的妖魔是什么尺棋? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任封锉,我火速辦了婚禮,結(jié)果婚禮上膘螟,老公的妹妹穿的比我還像新娘成福。我一直安慰自己,他們只是感情好荆残,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布奴艾。 她就那樣靜靜地躺著,像睡著了一般脊阴。 火紅的嫁衣襯著肌膚如雪握侧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天嘿期,我揣著相機與錄音品擎,去河邊找鬼。 笑死备徐,一個胖子當著我的面吹牛萄传,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜜猾,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼秀菱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蹭睡?” 一聲冷哼從身側(cè)響起衍菱,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肩豁,沒想到半個月后脊串,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡清钥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年琼锋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祟昭。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡缕坎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出篡悟,到底是詐尸還是另有隱情谜叹,我是刑警寧澤匾寝,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站叉谜,受9級特大地震影響旗吁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜停局,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一很钓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧董栽,春花似錦码倦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至擒抛,卻和暖如春推汽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背歧沪。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工歹撒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诊胞。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓暖夭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親撵孤。 傳聞我的和親對象是個殘疾皇子迈着,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容