中文分词模拟器

机考E卷200分题 - 中文分词模拟器

题目描述

给定一个连续不包含空格的字符串,该字符串仅包含英文小写字母及英文标点符号(逗号、分号、句号),同时给定词库,对该字符串进行精确分词。

说明:

1. 精确分词:字符串分词后,不会出现重叠。即"ilovechina",不同词库可分割为"i,love,china",“ilove,china”,不能分割出现重叠的"i,ilove,china",i 出现重叠

2. 标点符号不成词,仅用于断句

3. 词库:根据外部知识库统计出来的常用词汇例:dictionary = [“i”, “love”, “china”, “lovechina”, “ilove”]

4. 分词原则:采用分词顺序优先且最长匹配原则

“ilovechina”,假设分词结果 [i,ilove,lo,love,ch,china,lovechina],则输出 [ilove,china]

错误输出:[i,lovechina],原因:“ilove” > 优先于 “lovechina” 成词

错误输出:[i,love,china],原因:“ilove” > "i"遵循最长匹配原则

输入描述

第一行输入待分词语句
“ilovechina”

  • 字符串长度限制:0 < length < 256

第二行输入中文词库 “i,love,china,ch,na,ve,lo,this,is,this,word”

  • 词库长度限制:1 < length < 100000

输出描述

按顺序输出分词结果 “i,love,china”

用例1

输入

ilovechina
i,love,china,ch,na,ve,lo,this,is,the,word
12

输出

i,love,china
1

说明 无

用例2

输入

iat
i,love,china,ch,na,ve,lo,this,is,the,word,beauti,tiful,ful
12

输出

i,a,t
1

说明

单个字母,不在词库中且不成词则输出单个字母

用例3

输入

ilovechina,thewordisbeautiful
i,love,china,ch,na,ve,lo,this,is,the,word,beauti,tiful,ful
12

输出

i,love,china the,word,is,beauti,ful
1

说明

标点符号为英文标点符号

解题思路

题目的要求是给定一个连续的字符串,该字符串只包含英文小写字母和英文标点符号(逗号、分号、句号),同时给出一个词库。你需要根据这个词库将字符串进行分词。

这里的分词有两个原则:

1. 分词顺序优先:如果一个字符串可以被分割成多种可能的词序列,那么应该优先选择在词库中出现顺序较前的词。例如,如果词库是 [“i”, “love”, “china”, “lovechina”, “ilove”],那么字符串 “ilovechina” 应该被分割为 “ilove,china”,而不是 “i,lovechina”,因为 “ilove” 在词库中出现的顺序比 “lovechina” 要前。

2. 最长匹配原则:如果一个字符串可以被分割成多种可能的词序列,那么应该优先选择长度较长的词。例如,如果词库是 [“i”, “love”, “china”, “lovechina”, “ilove”],那么字符串 “ilovechina” 应该被分割为 “ilove,china”,而不是 “i,love,china”,因为 “ilove” 的长度比 “i” 要长。

注意,标点符号不会成为词的一部分,它们只用于断句。如果一个字符不在词库中,也不是标点符号,那么它会被当作一个单独的词。

用例模拟

ilovechina,thewordisbeautiful
i,love,china,ch,na,ve,lo,this,is,the,word,beauti,tiful,ful
12

在这个例子中,输入的句子是 “ilovechina,thewordisbeautiful”,字典中的单词是 “i”, “love”, “china”,
“ch”, “na”, “ve”, “lo”, “this”, “is”, “the”, “word”, “beauti”, “tiful”, “ful”。

1. 首先,将字典中的每个单词插入到 Trie 中。这个过程中,Trie 会根据字典中的单词构建出相应的路径。

2. 然后,开始遍历句子中的每个字符。首先遇到的字符是 ‘i’,在 Trie 中可以找到以 ‘i’ 为起点的单词 “i”,所以将 “i” 添加到结果中。

3. 接下来的字符是 ‘l’,在 Trie 中可以找到以 ‘l’ 为起点的最长单词 “love”,所以将 “love” 添加到结果中。

4. 然后的字符是 ‘c’,在 Trie 中可以找到以 ‘c’ 为起点的最长单词 “china”,所以将 “china” 添加到结果中。

5. 接下来的字符是 ‘,’,这是一个非字母字符,直接将其添加到结果中。

6. 然后的字符是 ‘t’,在 Trie 中可以找到以 ‘t’ 为起点的最长单词 “the”,所以将 “the” 添加到结果中。

7. 接下来的字符是 ‘w’,在 Trie 中可以找到以 ‘w’ 为起点的最长单词 “word”,所以将 “word” 添加到结果中。

8. 然后的字符是 ‘i’,在 Trie 中可以找到以 ‘i’ 为起点的最长单词 “is”,所以将 “is” 添加到结果中。

9. 接下来的字符是 ‘b’,在 Trie 中可以找到以 ‘b’ 为起点的最长单词 “beauti”,所以将 “beauti” 添加到结果中。

10. 最后的字符是 ‘f’,在 Trie 中可以找到以 ‘f’ 为起点的最长单词 “ful”,所以将 “ful” 添加到结果中。

11. 遍历完句子中的所有字符后,得到的结果是 “i,love,china,the,word,is,beauti,ful”。

所以,这个程序的输出应该是 “i,love,china,the,word,is,beauti,ful”。

C++

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm> // 添加这一行

using namespace std;

// 定义 TrieNode 类,每个节点包含一个布尔值 isWord 和一个 TrieNode 类型的数组 children
struct TrieNode {
    bool isWord;
    TrieNode* children[26];

    TrieNode() {
        isWord = false;
        for (int i = 0; i < 26; i++) {
            children[i] = nullptr;
        }
    }
};

// 创建 Trie 的根节点
TrieNode* root = new TrieNode();

// 插入方法,用于向 Trie 中插入一个单词
void insert(string word) {
    TrieNode* node = root;
    // 遍历单词中的每个字符
    for (char c : word) {
        // 如果当前字符对应的子节点为空,则创建一个新的子节点
        if (node->children[c - 'a'] == nullptr) {
            node->children[c - 'a'] = new TrieNode();
        }
        // 移动到下一个子节点
        node = node->children[c - 'a'];
    }
    // 标记当前节点为一个单词的结束
    node->isWord = true;
}

int main() {
    // 读取输入的句子,并将其转换为小写
    string sentence;
    getline(cin, sentence);
    transform(sentence.begin(), sentence.end(), sentence.begin(), ::tolower);

    // 读取输入的字典,字典中的单词以逗号分隔
    string dictionary;
    getline(cin, dictionary);
    stringstream ss(dictionary);
    string word;
    while (getline(ss, word, ',')) {
        insert(word);
    }

    vector<string> result;
    int i = 0;
    // 遍历句子中的每个字符
    while (i < sentence.size()) {
        // 如果当前字符不是字母,则直接将其添加到结果中
        if (!isalpha(sentence[i])) {
            result.push_back(sentence.substr(i, 1));
            i++;
            continue;
        }
        int j = sentence.size();
        // 从句子的末尾开始,寻找以 i 为起点的最长的在字典中存在的单词
        while (j > i) {
            TrieNode* node = root;
            bool isWord = true;
            for (int k = i; k < j; k++) {
                // 如果当前字符不是字母,或者在 Trie 中不存在对应的子节点,则说明当前的字符串不是一个单词
                if (!isalpha(sentence[k]) || node->children[sentence[k] - 'a'] == nullptr) {
                    isWord = false;
                    break;
                }
                // 移动到下一个子节点
                node = node->children[sentence[k] - 'a'];
            }
            // 如果找到了一个单词,则结束循环
            if (isWord && node->isWord) {
                break;
            }
            // 如果没有找到单词,则缩短当前的字符串
            j--;
        }
        // 如果没有找到单词,则将当前字符作为一个单独的单词添加到结果中
        if (j == i) {
            result.push_back(sentence.substr(i, 1));
            i++;
        } else {
            // 如果找到了单词,则将该单词添加到结果中
            result.push_back(sentence.substr(i, j - i));
            i = j;
        }
    }

    // 输出结果,单词之间以逗号分隔
    for (int i = 0; i < result.size(); i++) {
        if (i > 0) {
            cout << ",";
        }
        cout << result[i];
    }
    cout << endl;

    return 0;
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108

Java

import java.util.*;

public class Main {
    // 定义 TrieNode 类,每个节点包含一个布尔值 isWord 和一个 TrieNode 类型的数组 children
    static class TrieNode {
        boolean isWord;
        TrieNode[] children = new TrieNode[26];
    }

    // 创建 Trie 的根节点
    static TrieNode root = new TrieNode();

    // 插入方法,用于向 Trie 中插入一个单词
    public static void insert(String word) {
        TrieNode node = root;
        // 遍历单词中的每个字符
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            // 如果当前字符对应的子节点为空,则创建一个新的子节点
            if (node.children[c - 'a'] == null) {
                node.children[c - 'a'] = new TrieNode();
            }
            // 移动到下一个子节点
            node = node.children[c - 'a'];
        }
        // 标记当前节点为一个单词的结束
        node.isWord = true;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 读取输入的句子,并将其转换为小写
        String sentence = scanner.nextLine().toLowerCase();
        // 读取输入的字典,字典中的单词以逗号分隔
        String[] dictionary = scanner.nextLine().split(",");
        // 将字典中的每个单词插入到 Trie 中
        for (String word : dictionary) {
            insert(word.toLowerCase());
        }

        List<String> result = new ArrayList<>();
        int i = 0;
        // 遍历句子中的每个字符
        while (i < sentence.length()) {
            // 如果当前字符不是字母,则直接将其添加到结果中
            if (sentence.charAt(i) < 'a' || sentence.charAt(i) > 'z') {
                result.add(sentence.substring(i, i + 1));
                i++;
                continue;
            }
            int j = sentence.length();
            // 从句子的末尾开始,寻找以 i 为起点的最长的在字典中存在的单词
            while (j > i) {
                TrieNode node = root;
                boolean isWord = true;
                for (int k = i; k < j; k++) {
                    // 如果当前字符不是字母,或者在 Trie 中不存在对应的子节点,则说明当前的字符串不是一个单词
                    if (sentence.charAt(k) < 'a' || sentence.charAt(k) > 'z' || node.children[sentence.charAt(k) - 'a'] == null) {
                        isWord = false;
                        break;
                    }
                    // 移动到下一个子节点
                    node = node.children[sentence.charAt(k) - 'a'];
                }
                // 如果找到了一个单词,则结束循环
                if (isWord && node.isWord) {
                    break;
                }
                // 如果没有找到单词,则缩短当前的字符串
                j--;
            }
            // 如果没有找到单词,则将当前字符作为一个单独的单词添加到结果中
            if (j == i) {
                result.add(sentence.substring(i, i + 1));
                i++;
            } else {
                // 如果找到了单词,则将该单词添加到结果中
                result.add(sentence.substring(i, j));
                i = j;
            }
        }

        // 输出结果,单词之间以逗号分隔
        System.out.println(String.join(",", result));
    }
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586

javaScript

// 定义 TrieNode 类,每个节点包含一个布尔值 isWord 和一个 TrieNode 类型的数组 children
class TrieNode {
    constructor() {
        this.isWord = false; // 标记该节点是否为一个单词的结束
        this.children = new Array(26).fill(null); // 存储子节点的数组,每个元素对应一个字母
    }
}

// 创建 Trie 的根节点
let root = new TrieNode();

// 插入方法,用于向 Trie 中插入一个单词
function insert(word) {
    let node = root; // 从根节点开始
    for (let i = 0; i < word.length; i++) {
        let c = word.charCodeAt(i) - 'a'.charCodeAt(0); // 计算当前字符对应的索引
        // 如果当前字符对应的子节点为空,则创建一个新的子节点
        if (node.children[c] == null) {
            node.children[c] = new TrieNode();
        }
        // 移动到下一个子节点
        node = node.children[c];
    }
    // 标记当前节点为一个单词的结束
    node.isWord = true;
}

let readline = require('readline');
let rl = readline.createInterface({
    input: process.stdin, // 输入流
    output: process.stdout // 输出流
});

let lines = []; // 存储输入的每一行
rl.on('line', function (line) {
    lines.push(line); // 当读取到一行时,将其添加到 lines 数组中
}).on('close', function() { // 当读取完所有输入时
    let sentence = lines[0].toLowerCase(); // 获取句子,并将其转换为小写
    let dictionary = lines[1].split(","); // 获取字典,字典中的单词以逗号分隔
    for (let word of dictionary) {
        insert(word.toLowerCase()); // 将字典中的每个单词插入到 Trie 中
    }

    let result = []; // 存储结果
    let i = 0;
    // 遍历句子中的每个字符
    while (i < sentence.length) {
        // 如果当前字符不是字母,则直接将其添加到结果中
        if (sentence.charCodeAt(i) < 'a'.charCodeAt(0) || sentence.charCodeAt(i) > 'z'.charCodeAt(0)) {
            result.push(sentence.substring(i, i + 1));
            i++;
            continue;
        }
        let j = sentence.length;
        // 从句子的末尾开始,寻找以 i 为起点的最长的在字典中存在的单词
        while (j > i) {
            let node = root;
            let isWord = true;
            for (let k = i; k < j; k++) {
                // 如果当前字符不是字母,或者在 Trie 中不存在对应的子节点,则说明当前的字符串不是一个单词
                if (sentence.charCodeAt(k) < 'a'.charCodeAt(0) || sentence.charCodeAt(k) > 'z'.charCodeAt(0) || node.children[sentence.charCodeAt(k) - 'a'.charCodeAt(0)] == null) {
                    isWord = false;
                    break;
                }
                // 移动到下一个子节点
                node = node.children[sentence.charCodeAt(k) - 'a'.charCodeAt(0)];
            }
            // 如果找到了一个单词,则结束循环
            if (isWord && node.isWord) {
                break;
            }
            // 如果没有找到单词,则缩短当前的字符串
            j--;
        }
        // 如果没有找到单词,则将当前字符作为一个单独的单词添加到结果中
        if (j == i) {
            result.push(sentence.substring(i, i + 1));
            i++;
        } else {
            // 如果找到了单词,则将该单词添加到结果中
            result.push(sentence.substring(i, j));
            i = j;
        }
    }

    // 输出结果,单词之间以逗号分隔
    console.log(result.join(","));
});
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788

Python

# 定义 TrieNode 类,每个节点包含一个布尔值 is_word 和一个 TrieNode 类型的数组 children
class TrieNode:
    def __init__(self):
        self.is_word = False  # 标记该节点是否为一个单词的结束
        self.children = [None] * 26  # 存储子节点的数组,每个元素对应一个字母

# 创建 Trie 的根节点
root = TrieNode()

# 插入方法,用于向 Trie 中插入一个单词
def insert(word):
    node = root  # 从根节点开始
    for c in word:
        index = ord(c) - ord('a')  # 计算当前字符对应的索引
        # 如果当前字符对应的子节点为空,则创建一个新的子节点
        if node.children[index] is None:
            node.children[index] = TrieNode()
        # 移动到下一个子节点
        node = node.children[index]
    # 标记当前节点为一个单词的结束
    node.is_word = True

# 输入句子,并将其转换为小写
sentence = input().lower()
# 输入字典,字典中的单词以逗号分隔
dictionary = input().split(",")
for word in dictionary:
    insert(word.lower())  # 将字典中的每个单词插入到 Trie 中

result = []  # 存储结果
i = 0
# 遍历句子中的每个字符
while i < len(sentence):
    # 如果当前字符不是字母,则直接将其添加到结果中
    if not sentence[i].isalpha():
        result.append(sentence[i])
        i += 1
        continue
    j = len(sentence)
    # 从句子的末尾开始,寻找以 i 为起点的最长的在字典中存在的单词
    while j > i:
        node = root
        is_word = True
        for k in range(i, j):
            # 如果当前字符不是字母,或者在 Trie 中不存在对应的子节点,则说明当前的字符串不是一个单词
            if not sentence[k].isalpha() or node.children[ord(sentence[k]) - ord('a')] is None:
                is_word = False
                break
            # 移动到下一个子节点
            node = node.children[ord(sentence[k]) - ord('a')]
        # 如果找到了一个单词,则结束循环
        if is_word and node.is_word:
            break
        # 如果没有找到单词,则缩短当前的字符串
        j -= 1
    # 如果没有找到单词,则将当前字符作为一个单独的单词添加到结果中
    if j == i:
        result.append(sentence[i])
        i += 1
    else:
        # 如果找到了单词,则将该单词添加到结果中
        result.append(sentence[i:j])
        i = j

# 输出结果,单词之间以逗号分隔
print(",".join(result))
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566

C语言

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// 定义 TrieNode 结构体,每个节点包含一个布尔值 isWord 和一个 TrieNode 类型的数组 children
struct TrieNode {
    int isWord;
    struct TrieNode* children[26];
};

// 创建 Trie 的根节点
struct TrieNode* root;

// 插入方法,用于向 Trie 中插入一个单词
void insert(char* word) {
    struct TrieNode* node = root;
    // 遍历单词中的每个字符
    for (int i = 0; i < strlen(word); i++) {
        char c = word[i];
        // 如果当前字符对应的子节点为空,则创建一个新的子节点
        if (node->children[c - 'a'] == NULL) {
            node->children[c - 'a'] = (struct TrieNode*)calloc(1, sizeof(struct TrieNode));
        }
        // 移动到下一个子节点
        node = node->children[c - 'a'];
    }
    // 标记当前节点为一个单词的结束
    node->isWord = 1;
}

int main() {
    root = (struct TrieNode*)calloc(1, sizeof(struct TrieNode));

    // 读取输入的句子,并将其转换为小写
    char sentence[1000];
    fgets(sentence, 1000, stdin);
    for (int i = 0; i < strlen(sentence); i++) {
        sentence[i] = tolower(sentence[i]);
    }

    // 读取输入的字典,字典中的单词以逗号分隔
    char dictionary[1000];
    fgets(dictionary, 1000, stdin);
    char* word = strtok(dictionary, ",");
    while (word != NULL) {
        insert(word);
        word = strtok(NULL, ",");
    }

    char result[1000] = "";
    int i = 0;
    // 遍历句子中的每个字符
    while (i < strlen(sentence)) {
        // 如果当前字符不是字母,则直接将其添加到结果中
        if (!isalpha(sentence[i])) {
            strncat(result, &sentence[i], 1);
            i++;
            continue;
        }
        int j = strlen(sentence);
        // 从句子的末尾开始,寻找以 i 为起点的最长的在字典中存在的单词
        while (j > i) {
            struct TrieNode* node = root;
            int isWord = 1;
            for (int k = i; k < j; k++) {
                // 如果当前字符不是字母,或者在 Trie 中不存在对应的子节点,则说明当前的字符串不是一个单词
                if (!isalpha(sentence[k]) || node->children[sentence[k] - 'a'] == NULL) {
                    isWord = 0;
                    break;
                }
                // 移动到下一个子节点
                node = node->children[sentence[k] - 'a'];
            }
            // 如果找到了一个单词,则结束循环
            if (isWord && node->isWord) {
                break;
            }
            // 如果没有找到单词,则缩短当前的字符串
            j--;
        }
        // 如果没有找到单词,则将当前字符作为一个单独的单词添加到结果中
        if (j == i) {
            strncat(result, &sentence[i], 1);
            i++;
        } else {
            // 如果找到了单词,则将该单词添加到结果中
            char temp[100];
            strncpy(temp, &sentence[i], j - i);
            temp[j - i] = '\0';
            strcat(result, temp);
            i = j;
        }
        strcat(result, ",");
    }

    // 输出结果,单词之间以逗号分隔
    printf("%s\n", result);

    return 0;
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101

编程精选网(www.codehuber.com),程序员的终身学习网站已上线!

如果这篇【文章】有帮助到你,希望可以给【JavaGPT】点个赞👍,创作不易,如果有对【后端技术】、【前端领域】感兴趣的小可爱,也欢迎关注❤️❤️❤️ 【JavaGPT】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💝💝💝!

本文由博客一文多发平台 OpenWrite 发布!

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

推荐阅读更多精彩内容