Leetcode Design Tag

Design

// LRU Cache
// 99 ms
class LRUCache {
private:
    int capacity;
    int size;
    unordered_map<int, int> cache;
    unordered_map<int, list<int>::iterator> position;
    list<int> visited;
    
public:
    LRUCache(int capacity) {
        this->capacity = capacity;
        this->size = 0;
    }
    
    int get(int key) {
        if (cache.find(key) != cache.end()) {
            visit(key);
            return cache[key];
        }
        return -1;
    }
    
    void put(int key, int value) {
        if (cache.find(key) != cache.end()) {
            cache[key] = value;
            visit(key);
        } else {
            if (size == capacity) 
                invalidate();
            cache[key] = value;
            visited.push_front(key);
            position[key] = visited.begin();
            size++;
        }
    }
    
    void visit(int key) {
        list<int>::iterator iter = position[key];
        visited.erase(iter);
        visited.push_front(key);
        position[key] = visited.begin();
    }
    
    void invalidate() {
        int key = visited.back();
        visited.pop_back();
        cache.erase(key);
        position.erase(key);
        size--;
    }
};
// 86 ms
class LRUCache {
private:
    struct CacheNode {
        int key;
        int value;
        CacheNode(int k, int v) : key(k), value(v) {}
    };
    
public:
    LRUCache(int capacity) {
        this->capacity = capacity;
    }
    
    int get(int key) {
        if (cacheMap.find(key) != cacheMap.end()) {
            cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]);
            cacheMap[key] = cacheList.begin();
            return cacheMap[key]->value;
        } else {
            return -1;
        }
    }
    
    void put(int key, int value) {
        if (capacity == 0)
            return;
        if (cacheMap.find(key) != cacheMap.end()) {
            cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]);
            cacheMap[key] = cacheList.begin();
            cacheMap[key]->value = value;
        } else {
            if (cacheMap.size() == capacity) {
                cacheMap.erase(cacheList.back().key);
                cacheList.pop_back();
            }
            cacheList.emplace_front(CacheNode(key, value)); // emplace_front比push_front快
            cacheMap[key] = cacheList.begin();
        }
    }

private:
    int capacity;
    list<CacheNode> cacheList;
    unordered_map<int, list<CacheNode>::iterator> cacheMap;   
};
// LFU Cache
// 99ms
class LFUCache {
private:
    struct FrequencyListNode {
        int frequency;
        list<int> visited;
        FrequencyListNode(int f) : frequency(f) {}
    };
    
    int capacity;
    int size;
    unordered_map<int, int> cache;
    list<FrequencyListNode> frequencyList;
    unordered_map<int, list<FrequencyListNode>::iterator> index1;
    unordered_map<int, list<int>::iterator> index2;
    
public:
    LFUCache(int capacity) {
        this->capacity = capacity;
        this->size = 0;
    }
    
    int get(int key) {
        if (cache.find(key) != cache.end()) {
            visit(key);
            return cache[key];
        }
        return -1;
    }
    
    void put(int key, int value) {
        if (capacity == 0)
            return;
        if (cache.find(key) != cache.end()) {
            cache[key] = value;
            visit(key);
        } else {
            if (size == capacity) 
                invalidate();
            cache[key] = value;
            if (frequencyList.empty() || (frequencyList.front()).frequency > 1)
                frequencyList.push_front(FrequencyListNode(1));
            (frequencyList.front()).visited.push_front(key);
            index1[key] = frequencyList.begin();
            index2[key] = (frequencyList.begin())->visited.begin();
            size++;
        }
    }
    
    void visit(int key) {
        list<FrequencyListNode>::iterator iter1 = index1[key];
        list<int>::iterator iter2 = index2[key];
        int frequency = iter1->frequency;
        iter1->visited.erase(iter2);
        if (iter1->visited.empty())
            iter1 = frequencyList.erase(iter1); // Important!: erase后重新赋给iter1
        else
            iter1++;
        if (iter1 == frequencyList.end() || iter1->frequency > frequency + 1)
            iter1 = frequencyList.insert(iter1, FrequencyListNode(frequency + 1)); // Important!: insert后重新赋给iter1
        iter1->visited.push_front(key);
        index1[key] = iter1;
        index2[key] = iter1->visited.begin();
    }
    
    void invalidate() {
        int key = (frequencyList.begin())->visited.back();
        (frequencyList.begin())->visited.pop_back();
        if ((frequencyList.begin())->visited.empty())
            frequencyList.pop_front();
        cache.erase(key);
        index1.erase(key);
        index2.erase(key);
        size--;
    }
};
// 168 ms
class LFUCache {
private:
    struct CacheNode {
        int key;
        int value;
        CacheNode(int k, int v) : key(k), value(v) {}
    };
    
    struct CacheBucket {
        int frequency;
        list<CacheNode> cacheList;
        unordered_map<int, list<CacheNode>::iterator> cacheMap;  // map<key, cacheNode> (second-layer index)
        CacheBucket(int f) : frequency(f) {}
    };
    
public:
    LFUCache(int capacity) {
        this->capacity = capacity;
    }
    
    int get(int key) {
        if (cacheMap.find(key) != cacheMap.end()) {
            list<CacheBucket>::iterator bucket = cacheMap[key];
            list<CacheNode>::iterator node = bucket->cacheMap[key];
            int value = node->value;
            inc(bucket, key, value);
            return value;
        } else {
            return -1;
        }
    }
    
    void put(int key, int value) {
        if (capacity == 0) return;
        if (cacheMap.find(key) != cacheMap.end()) {
            list<CacheBucket>::iterator bucket = cacheMap[key];
            inc(bucket, key, value);
        } else {
            if (cacheMap.size() == capacity) {
                cache.front().cacheMap.erase(cache.front().cacheList.back().key);
                cacheMap.erase(cache.front().cacheList.back().key);
                cache.front().cacheList.pop_back();
                if (cache.front().cacheMap.empty())
                    cache.pop_front();
            }
            if (cache.empty() || cache.front().frequency > 1)
                cache.insert(cache.begin(), CacheBucket(1));
            cache.front().cacheList.push_front(CacheNode(key, value));
            cache.front().cacheMap[key] = cache.front().cacheList.begin();
            cacheMap[key] = cache.begin();
        }
    }
    
    void inc(list<CacheBucket>::iterator &bucket, int key, int value) { // frequency + 1
        int frequency = bucket->frequency;
        bucket->cacheList.erase(bucket->cacheMap[key]);
        bucket->cacheMap.erase(key);
        
        if (bucket->cacheMap.empty())
            bucket = cache.erase(bucket);
        else
            bucket++;
        if (bucket == cache.end() || bucket->frequency > frequency + 1) {
            cache.insert(bucket, CacheBucket(frequency + 1));
            bucket--;
        }
        bucket->cacheList.push_front(CacheNode(key, value));
        bucket->cacheMap[key] = bucket->cacheList.begin();
        cacheMap[key] = bucket;
    }
private:
    int capacity;
    list<CacheBucket> cache;
    unordered_map<int, list<CacheBucket>::iterator> cacheMap;  // map<key, cacheBucket> (first-layer index)
};
// Find Median from Data Stream
// 考虑两个优先队列(最大最小堆)
class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {}
    
    void addNum(int num) {
        if (maxpq.empty() || num <= maxpq.top()) {
            maxpq.push(num);
            if (maxpq.size() > minpq.size() + 1) {
                int median = maxpq.top();
                maxpq.pop();
                minpq.push(median);
            }
        } else {
            minpq.push(num);
            if (maxpq.size() < minpq.size()) {
                int median = minpq.top();
                minpq.pop();
                maxpq.push(median);
            }
        }        
    }
    
    double findMedian() {
        if (maxpq.size() == minpq.size())
            return ((double)maxpq.top() + (double)minpq.top()) / 2;
        else
            return maxpq.top();
    }
private:
    priority_queue<int> maxpq; // has smaller half of the numbers
    priority_queue<int, vector<int>, greater<int>> minpq; // has larger half of the numbers
    // Ensure that maxpq.size() == minpq.size() or maxpq.size() == minpq.size() + 1
};
// Insert Delete GetRandom O(1)
class RandomizedSet {
public:
    /** Initialize your data structure here. */
    RandomizedSet() {
        
    }
    
    /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
    bool insert(int val) {
        if (pos.find(val) != pos.end())
            return false;
        elements.push_back(val);
        pos[val] = elements.size() - 1;
        return true;
    }
    
    /** Removes a value from the set. Returns true if the set contained the specified element. */
    bool remove(int val) {
        if (pos.find(val) == pos.end())
            return false;
        if (pos[val] < elements.size() - 1) {
            int replace_val = elements.back();
            pos[replace_val] = pos[val];
            elements[pos[val]] = replace_val;
        }
        pos.erase(val);
        elements.pop_back();
        return true;
    }
    
    /** Get a random element from the set. */
    int getRandom() {
        return elements[rand() % elements.size()];
    }
private:
    vector<int> elements;
    unordered_map<int, int> pos;
};
// Insert Delete GetRandom O(1) - Duplicates allowed
// 56 ms
class RandomizedCollection {
private:
    struct CacheNode {
        int frequency;
        list<int> pos;
        unordered_map<int, list<int>::iterator> posCache;
        CacheNode() {} // Important!: 要保留默认构造函数
        CacheNode(int f, int p) {
            frequency = f;
            pos.push_back(p);
            posCache[p] = --pos.end(); // Important!: 没有pos.end() - 1,pos.end()--也是错的
        }
        void inc(int p) {
            frequency++;
            pos.push_back(p);
            posCache[p] = --pos.end();
        }
        int dec() {
            frequency--;
            int p = pos.back();
            pos.pop_back();
            posCache.erase(p);
            return p;
        }
        void update(int p, int q) {
            pos.erase(posCache[p]);
            posCache.erase(p);
            pos.push_back(q);
            posCache[q] = --pos.end();
        }
    };
    
public:
    /** Initialize your data structure here. */
    RandomizedCollection() {
        size = 0;
    }
    
    /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
    bool insert(int val) {
        elements.push_back(val);
        if (cache.find(val) != cache.end()) {
            cache[val].inc(size++);
            return false;
        } else {
            cache[val] = CacheNode(1, size++); // 因为这里会先调用默认构造函数,再调用operator =
            return true;
        }
    }
    
    /** Removes a value from the collection. Returns true if the collection contained the specified element. */
    bool remove(int val) {
        if (cache.find(val) == cache.end())
            return false;
        int p = cache[val].dec();
        if (cache[val].frequency == 0)
            cache.erase(val);
        if (p < size - 1) {
            int replace_val = elements[size - 1];
            elements[p] = replace_val;
            cache[replace_val].update(size - 1, p);
        }
        elements.pop_back();
        size--;
        return true;
    }
    
    /** Get a random element from the collection. */
    int getRandom() {
        return elements[rand() % size];
    }

private:
    unordered_map<int, CacheNode> cache;
    vector<int> elements;
    int size;
};
// All O`one Data Structure
class AllOne {
public:
    struct CacheNode {
        int value;
        list<string> keys;
        CacheNode() {}
        CacheNode(int v, string key) : value(v) { keys.push_back(key); }
    };
    /** Initialize your data structure here. */
    AllOne() {
        
    }
    
    /** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */
    void inc(string key) {
        if (index1.find(key) == index1.end()) {
            if (cache.empty() || cache.front().value > 1)
                cache.push_front(CacheNode(1, key));
            else
                cache.front().keys.push_front(key);
            index1[key] = cache.begin();
            index2[key] = cache.front().keys.begin();
        } else {
            list<CacheNode>::iterator iter1 = index1[key];
            list<string>::iterator iter2 = index2[key];
            int value = iter1->value;
            iter1->keys.erase(iter2);
            if (iter1->keys.empty())
                iter1 = cache.erase(iter1);
            else
                iter1++;
            if (iter1 == cache.end() || iter1->value > value + 1)
                iter1 = cache.insert(iter1, CacheNode(value + 1, key));
            else
                iter1->keys.push_front(key);
            index1[key] = iter1;
            index2[key] = iter1->keys.begin();
        }
    }
    
    /** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */
    void dec(string key) {
        if (index1.find(key) != index1.end()) {
            list<CacheNode>::iterator iter1 = index1[key];
            list<string>::iterator iter2 = index2[key];
            int value = iter1->value;
            iter1->keys.erase(iter2);
            if (iter1->keys.empty())
                iter1 = cache.erase(iter1);
            if (value == 1) {
                index1.erase(key);
                index2.erase(key);
                return;
            }
            if (iter1 == cache.begin()) {
                cache.push_front(CacheNode(value - 1, key));
                iter1 = cache.begin();
            } else if ((--iter1)->value < value - 1) {
                iter1 = cache.insert(++iter1, CacheNode(value - 1, key));
            } else {
                iter1->keys.push_front(key);
            }
            index1[key] = iter1;
            index2[key] = iter1->keys.begin();
        }
    }
    
    /** Returns one of the keys with maximal value. */
    string getMaxKey() {
        return cache.back().keys.front();
    }
    
    /** Returns one of the keys with Minimal value. */
    string getMinKey() {
        return cache.front().keys.front();
    }
private:
    list<CacheNode> cache;
    unordered_map<string, list<CacheNode>::iterator> index1;
    unordered_map<string, list<string>::iterator> index2;
};
// Peeking Iterator
// Since Iterator has a copy constructor, we can just use it
// Below is the interface for Iterator, which is already defined for you.
// **DO NOT** modify the interface for Iterator.
class Iterator {
    struct Data;
    Data* data;
public:
    Iterator(const vector<int>& nums);
    Iterator(const Iterator& iter);
    virtual ~Iterator();
    // Returns the next element in the iteration.
    int next();
    // Returns true if the iteration has more elements.
    bool hasNext() const;
};

class PeekingIterator : public Iterator {
public:
    PeekingIterator(const vector<int>& nums) : Iterator(nums) {
        // Initialize any member here.
        // **DO NOT** save a copy of nums and manipulate it directly.
        // You should only use the Iterator interface methods.
    }

    // Returns the next element in the iteration without advancing the iterator.
    int peek() {
        return Iterator(*this).next();
    }

    // hasNext() and next() should behave the same as in the Iterator interface.
    // Override them if needed.
    int next() {
        return Iterator::next();
    }

    bool hasNext() const {
        return Iterator::hasNext();
    }
};
// Min Stack
class MinStack {
private:
    struct StackNode {
        int value;
        int min;
        StackNode *next;
        StackNode(int value, int min, StackNode *next) : value(value), min(min), next(next) {}
    };
    StackNode *head;
public:
    /** initialize your data structure here. */
    MinStack() {
        head = NULL;
    }
    void push(int x) {
        if (head == NULL)
            head = new StackNode(x, x, NULL);
        else {
            head = new StackNode(x, min(x, getMin()), head);
        }
    }
    void pop() {
        if (head) {
            StackNode *newhead = head->next;
            free(head);
            head = newhead;
        }
    }
    int top() {
        if (head)
            return head->value;
    }
    int getMin() {
        if (head)
            return head->min;
    }
};
class MinStack {
private:
    stack<int> s1;
    stack<int> s2;
public:
    void push(int x) {
        s1.push(x);
        if (s2.empty() || x <= getMin())  s2.push(x);       
    }
    void pop() {
        if (s1.top() == getMin())  s2.pop();
        s1.pop();
    }
    int top() {
        return s1.top();
    }
    int getMin() {
        return s2.top();
    }
};
// Implement Queue using Stacks
class MyQueue {
public:
    /** Initialize your data structure here. */
    MyQueue() {   
    }
    /** Push element x to the back of queue. */
    void push(int x) {
        input.push(x);
    }
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        int result = peek();
        output.pop();
        return result;
    }
    /** Get the front element. */
    int peek() {
        if (output.empty())
            transfer();
        return output.top();
    }
    /** Returns whether the queue is empty. */
    bool empty() {
        return input.empty() && output.empty();
    }
    void transfer() {
        while (!input.empty()) {
            output.push(input.top());
            input.pop();
        }
    }
private:
    stack<int> input, output;
};
// Implement Stack using Queues
class MyStack {
public:
    /** Initialize your data structure here. */
    MyStack() { 
    }
    /** Push element x onto stack. */
    void push(int x) {
        q.push(x);
    }
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        queue<int> p;
        while (q.size() > 1) {
            p.push(q.front());
            q.pop();
        }
        int result = q.front();
        q = p;
        return result;
    }
    /** Get the top element. */
    int top() {
        int result;
        queue<int> p;
        while (!q.empty()) {
            result = q.front();
            p.push(q.front());
            q.pop();
        }
        q = p;
        return result;
    }
    /** Returns whether the stack is empty. */
    bool empty() {
        return q.empty();
    }
private:
    queue<int> q;
};
// Flatten Nested List Iterator
class NestedIterator {
public:
    NestedIterator(vector<NestedInteger> &nestedList) {
        initialize(nestedList);
        pos = 0;
    }

    int next() {
        return vec[pos++];
    }

    bool hasNext() {
        return pos != vec.size();
    }
private:
    vector<int> vec;
    int pos;
    void initialize(vector<NestedInteger> &nestedList) {
        for (NestedInteger i : nestedList) {
            if (i.isInteger())
                vec.push_back(i.getInteger());
            else
                initialize(i.getList());
        }
    }
};
class NestedIterator {
public:
    NestedIterator(vector<NestedInteger> &nestedList) {
        if (!nestedList.empty()) {
            s.push(make_pair(nestedList.begin(), nestedList.end()));
            adjust();
        }
    }

    int next() {
        vector<NestedInteger>::iterator ib = s.top().first, ie = s.top().second, iter;
        s.pop();
        int res = ib->getInteger();
        ib++;
        if (ib != ie)
            s.push(make_pair(ib, ie));
        adjust();
        return res;
    }

    bool hasNext() {
        return !s.empty();
    }
private:
    stack<pair<vector<NestedInteger>::iterator, vector<NestedInteger>::iterator>> s;
    void adjust() {
        while (!s.empty() && !s.top().first->isInteger()) {
            vector<NestedInteger>::iterator ib = s.top().first, ie = s.top().second, iter;
            s.pop();
            iter = ib;
            ib++;
            if (ib != ie)
                s.push(make_pair(ib, ie));
            if (!iter->getList().empty())
                s.push(make_pair(iter->getList().begin(), iter->getList().end()));
        }
    }
};
class NestedIterator {
public:
    NestedIterator(vector<NestedInteger> &nestedList) {
        s.push(make_pair(nestedList.begin(), nestedList.end()));
        adjust();
    }

    int next() {
        int res = s.top().first->getInteger();
        s.top().first++;
        adjust();
        return res;
    }

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

推荐阅读更多精彩内容