• [LeetCode] 855. Exam Room 考场


    In an exam room, there are N seats in a single row, numbered 0, 1, 2, ..., N-1.

    When a student enters the room, they must sit in the seat that maximizes the distance to the closest person.  If there are multiple such seats, they sit in the seat with the lowest number.  (Also, if no one is in the room, then the student sits at seat number 0.)

    Return a class ExamRoom(int N) that exposes two functions: ExamRoom.seat() returning an int representing what seat the student sat in, and ExamRoom.leave(int p) representing that the student in seat number p now leaves the room.  It is guaranteed that any calls to ExamRoom.leave(p) have a student sitting in seat p.

    Example 1:

    Input: ["ExamRoom","seat","seat","seat","seat","leave","seat"], [[10],[],[],[],[],[4],[]]
    Output: [null,0,9,4,2,null,5]
    Explanation:
    ExamRoom(10) -> null
    seat() -> 0, no one is in the room, then the student sits at seat number 0.
    seat() -> 9, the student sits at the last seat number 9.
    seat() -> 4, the student sits at the last seat number 4.
    seat() -> 2, the student sits at the last seat number 2.
    leave(4) -> null
    seat() -> 5, the student sits at the last seat number 5.​​​​​​​

    Note:

    1. 1 <= N <= 10^9
    2. ExamRoom.seat() and ExamRoom.leave() will be called at most 10^4 times across all test cases.
    3. Calls to ExamRoom.leave(p) are guaranteed to have a student currently sitting in seat number p.

    在一个考场中,有N个座位在一排,当学生进入房间时,他们必须坐在与最近的人距离最大的座位上。 如果有多个这样的座位,他们就坐在座位编号最小的座位上。(另外,如果没有人在房间里,那么学生就坐在0号座位上。)实现一个类ExamRoom(int N),含有2个函数,ExamRoom.seat()返回学生应该坐的位置和ExamRoom.leave(int p)返回离开座位的学生。

    解法1:最大堆, T: seat: O(logn), leave O(n),S: O(n)。用一个max heap来记录所有两个相邻位置的间距,每次进来一个学生就pop出堆顶的位置,然后分配中间位子给学生,同时用一个数组记录当前位子的学生,再把新形成的两个相邻位置push到heap。当学生离开时,从数组中找到相应位置的学生,从数组中去除,同时去除heap中由这个位置形成的两个间距距离。

    解法2: Use a list L to record the index of seats where people sit. T: O(N) for seat() and leave()

    seat():
    1. find the biggest distance at the start, at the end and in the middle.
    2. insert index of seat
    3. return index

    leave(p): pop out p

    Java:

        int N;
        ArrayList<Integer> L = new ArrayList<>();
        public ExamRoom(int n) {
            N = n;
        }
    
        public int seat() {
            if (L.size() == 0) {
                L.add(0);
                return 0;
            }
            int d = Math.max(L.get(0), N - 1 - L.get(L.size() - 1));
            for (int i = 0; i < L.size() - 1; ++i) d = Math.max(d, (L.get(i + 1) - L.get(i)) / 2);
            if (L.get(0) == d) {
                L.add(0, 0);
                return 0;
            }
            for (int i = 0; i < L.size() - 1; ++i)
                if ((L.get(i + 1) - L.get(i)) / 2 == d) {
                    L.add(i + 1, (L.get(i + 1) + L.get(i)) / 2);
                    return L.get(i + 1);
                }
            L.add(N - 1);
            return N - 1;
        }
    
        public void leave(int p) {
            for (int i = 0; i < L.size(); ++i) if (L.get(i) == p) L.remove(i);
        }  

    Java:

    // PriorityQueue
    class ExamRoom {
        PriorityQueue<Interval> pq;
        int N;
    
        class Interval {
            int x, y, dist;
            public Interval(int x, int y) {
                this.x = x;
                this.y = y;
                if (x == -1) {
                    this.dist = y;
                } else if (y == N) {
                    this.dist = N - 1 - x;
                } else {
                    this.dist = Math.abs(x - y) / 2;    
                }
            }
        }
    
        public ExamRoom(int N) {
            this.pq = new PriorityQueue<>((a, b) -> a.dist != b.dist? b.dist - a.dist : a.x - b.x);
            this.N = N;
            pq.add(new Interval(-1, N));
        }
    
        // O(logn): poll top candidate, split into two new intervals
        public int seat() {
            int seat = 0;
            Interval interval = pq.poll();
            if (interval.x == -1) seat = 0;
            else if (interval.y == N) seat = N - 1;
            else seat = (interval.x + interval.y) / 2; 
            
            pq.offer(new Interval(interval.x, seat));
            pq.offer(new Interval(seat, interval.y));
                
            return seat;
        }
        
        // O(n)Find head and tail based on p. Delete and merge two ends
        public void leave(int p) {
            Interval head = null, tail = null;
            List<Interval> intervals = new ArrayList<>(pq);
            for (Interval interval : intervals) {
                if (interval.x == p) tail = interval;
                if (interval.y == p) head = interval;
                if (head != null && tail != null) break;
            }
            // Delete
            pq.remove(head);
            pq.remove(tail);
            // Merge
            pq.offer(new Interval(head.x, tail.y));
        }
    }
    

    Python:

    # Time:  seat:  O(logn) on average,
    #        leave: O(logn)
    # Space: O(n)
    
    import heapq
    
    LEN, POS, L, R = range(4)
    LEFT, RIGHT = range(2)
    
    
    class ExamRoom(object):
    
        def __init__(self, N):
            """
            :type N: int
            """
            self.__num = N
            self.__max_heap = [(-self.__num, 0, -1, self.__num)]
            self.__seats = {-1: [-1, self.__num],
                            self.__num: [-1, self.__num]}
    
        def seat(self):
            """
            :rtype: int
            """
            while self.__max_heap[0][L] not in self.__seats or 
                    self.__max_heap[0][R] not in self.__seats or 
                    self.__seats[self.__max_heap[0][L]][RIGHT] != 
                    self.__max_heap[0][R] or 
                    self.__seats[self.__max_heap[0][R]][LEFT] != 
                    self.__max_heap[0][L]:
                heapq.heappop(self.__max_heap)  # lazy deletion
    
            curr = heapq.heappop(self.__max_heap)
            if curr[L] == -1 and curr[R] == self.__num:
                heapq.heappush(self.__max_heap, (-(curr[R]-1),
                                                 curr[R]-1,
                                                 curr[L]+1, curr[R]))
            elif curr[L] == -1:
                heapq.heappush(self.__max_heap, (-(curr[R]//2),
                                                 curr[R]//2,
                                                 curr[L]+1, curr[R]))
            elif curr[R] == self.__num:
                heapq.heappush(self.__max_heap, (-((curr[R]-1-curr[L])//2),
                                                 (curr[R]-1-curr[L])//2+curr[L],
                                                 curr[L], curr[R]-1))
            else:
                heapq.heappush(self.__max_heap, (-((curr[POS]-curr[L])//2),
                                                 (curr[POS]-curr[L])//2+curr[L],
                                                 curr[L], curr[POS]))
                heapq.heappush(self.__max_heap, (-((curr[R]-curr[POS])//2),
                                                 (curr[R]-curr[POS])//2+curr[POS],
                                                 curr[POS], curr[R]))
            self.__seats[curr[POS]] = [curr[L], curr[R]]
            self.__seats[curr[L]][RIGHT] = curr[POS]
            self.__seats[curr[R]][LEFT] = curr[POS]
            return curr[POS]
    
        def leave(self, p):
            """
            :type p: int
            :rtype: void
            """
            neighbors = self.__seats[p]
            self.__seats.pop(p)
            if neighbors[LEFT] == -1 and neighbors[RIGHT] == self.__num:
                heapq.heappush(self.__max_heap,
                               (-neighbors[RIGHT],
                                neighbors[LEFT]+1,
                                neighbors[LEFT], neighbors[RIGHT]))
            elif neighbors[LEFT] == -1:
                heapq.heappush(self.__max_heap,
                               (-neighbors[RIGHT],
                                neighbors[LEFT]+1,
                                neighbors[LEFT], neighbors[RIGHT]))
            elif neighbors[RIGHT] == self.__num:
                heapq.heappush(self.__max_heap,
                               (-(neighbors[RIGHT]-1-neighbors[LEFT]),
                                neighbors[RIGHT]-1,
                                neighbors[LEFT], neighbors[RIGHT]))
            else:
                heapq.heappush(self.__max_heap,
                               (-((neighbors[RIGHT]-neighbors[LEFT])//2),
                                (neighbors[RIGHT]-neighbors[LEFT])//2 +
                                neighbors[LEFT],
                                neighbors[LEFT], neighbors[RIGHT]))
            self.__seats[neighbors[LEFT]][RIGHT] = neighbors[RIGHT]
            self.__seats[neighbors[RIGHT]][LEFT] = neighbors[LEFT]  

    Python:

    def __init__(self, N):
            self.N, self.L = N, []
    
        def seat(self):
            N, L = self.N, self.L
            if not L: res = 0
            else:
                d, res = L[0], 0
                for a, b in zip(L, L[1:]):
                    if (b - a) / 2 > d:
                        d, res = (b - a) / 2, (b + a) / 2
                if N - 1 - L[-1] > d: res = N - 1
            bisect.insort(L, res)
            return res
    
        def leave(self, p):
            self.L.remove(p)  

    Python: O(log n) time for both seat() and leave() with heapq and dicts

    from heapq import heappop, heappush
    
    
    class ExamRoom(object):
    
        def __init__(self, N):
            """
            :type N: int
            """
            self.N = N
            self.heap = []
            self.avail_first = {}
            self.avail_last = {}
            self.put_segment(0, self.N - 1)
    
        def put_segment(self, first, last):
    
            if first == 0 or last == self.N - 1:
                priority = last - first
            else:
                priority = (last - first) // 2
    
            segment = [-priority, first, last, True]
    
            self.avail_first[first] = segment
            self.avail_last[last] = segment
    
            heappush(self.heap, segment)
    
        def seat(self):
            """
            :rtype: int
            """
            while True:
                _, first, last, is_valid = heappop(self.heap)
    
                if is_valid:
                    del self.avail_first[first]
                    del self.avail_last[last]
                    break
    
            if first == 0:
                ret = 0
                if first != last:
                    self.put_segment(first + 1, last)
    
            elif last == self.N - 1:
                ret = last
                if first != last:
                    self.put_segment(first, last - 1)
    
            else:
                ret = first + (last - first) // 2
    
                if ret > first:
                    self.put_segment(first, ret - 1)
    
                if ret < last:
                    self.put_segment(ret + 1, last)
    
            return ret
    
        def leave(self, p):
            """
            :type p: int
            :rtype: void
            """
            first = p
            last = p
    
            left = p - 1
            right = p + 1
    
            if left >= 0 and left in self.avail_last:
                segment_left = self.avail_last.pop(left)
                segment_left[3] = False
                first = segment_left[1]
    
            if right < self.N and right in self.avail_first:
                segment_right = self.avail_first.pop(right)
                segment_right[3] = False
                last = segment_right[2]
    
            self.put_segment(first, last)
    

    C++:

     int N;
        vector<int> L;
        ExamRoom(int n) {
            N = n;
        }
    
        int seat() {
            if (L.size() == 0) {
                L.push_back(0);
                return 0;
            }
            int d = max(L[0], N - 1 - L[L.size() - 1]);
            for (int i = 0; i < L.size() - 1; ++i) d = max(d, (L[i + 1] - L[i]) / 2);
            if (L[0] == d) {
                L.insert(L.begin(), 0);
                return 0;
            }
            for (int i = 0; i < L.size() - 1; ++i)
                if ((L[i + 1] - L[i]) / 2 == d) {
                    L.insert(L.begin() + i + 1, (L[i + 1] + L[i]) / 2);
                    return L[i + 1];
                }
            L.push_back(N - 1);
            return N - 1;
        }
    
        void leave(int p) {
            for (int i = 0; i < L.size(); ++i) if (L[i] == p) L.erase(L.begin() + i);
        }
    

    C++:  

    // Time:  seat:  O(logn),
    //        leave: O(logn)
    // Space: O(n)
    
    class ExamRoom {
    public:
        ExamRoom(int N) : num_(N) {
            segment_iters_[make_pair(-1, num_)] = 
                max_bst_.emplace(make_shared<Segment>(num_, 0, -1, num_));
            seats_[-1] = make_pair(-1, num_);
            seats_[num_] = make_pair(-1, num_);
        }
        
        int seat() {
            const auto curr = *max_bst_.begin(); max_bst_.erase(max_bst_.begin());
            segment_iters_.erase(make_pair(curr->l, curr->r));
            if (curr->l == -1 && curr->r == num_) {
                segment_iters_[make_pair(curr->l + 1, curr->r)] = max_bst_.emplace(
                    make_shared<Segment>(curr->r - 1,
                                         curr->r - 1,
                                         curr->l + 1, curr->r));
            } else if (curr->l == -1) {
                segment_iters_[make_pair(curr->l + 1, curr->r)] = max_bst_.emplace(
                    make_shared<Segment>(curr->r / 2,
                                         curr->r / 2,
                                         curr->l + 1, curr->r));
            } else if (curr->r == num_) {
                segment_iters_[make_pair(curr->l, curr->r - 1)] = max_bst_.emplace(
                    make_shared<Segment>((curr->r - 1 - curr->l) / 2,
                                         (curr->r - 1 - curr->l) / 2 + curr->l,
                                         curr->l, curr->r - 1)); 
            } else {
                segment_iters_[make_pair(curr->l, curr->pos)] = max_bst_.emplace(
                    make_shared<Segment>((curr->pos - curr->l) / 2,
                                         (curr->pos - curr->l) / 2 + curr->l,
                                         curr->l, curr->pos));
                segment_iters_[make_pair(curr->pos, curr->r)] = max_bst_.emplace(
                    make_shared<Segment>((curr->r - curr->pos) / 2,
                                         (curr->r - curr->pos) / 2 + curr->pos,
                                         curr->pos, curr->r));
            }
            seats_[curr->pos] = make_pair(curr->l, curr->r);
            seats_[curr->l].second = curr->pos;
            seats_[curr->r].first = curr->pos;
            return curr->pos;
        }
        
        void leave(int p) {
            const auto neighbors = seats_[p];
            seats_.erase(p);
            const auto& left_segment = make_pair(neighbors.first, p);
            if (segment_iters_.count(left_segment)) {
                max_bst_.erase(segment_iters_[left_segment]); segment_iters_.erase(left_segment);
            }
            const auto& right_segment = make_pair(p, neighbors.second);
            if (segment_iters_.count(right_segment)) {
                max_bst_.erase(segment_iters_[right_segment]); segment_iters_.erase(right_segment);
            }
            
            if (neighbors.first == -1 && neighbors.second == num_) {
                segment_iters_[neighbors] = max_bst_.emplace(
                    make_shared<Segment>(neighbors.second,
                                         neighbors.first + 1, 
                                         neighbors.first, neighbors.second));
            } else if (neighbors.first == -1) {
                segment_iters_[neighbors] = max_bst_.emplace(
                    make_shared<Segment>(neighbors.second,
                                         neighbors.first + 1,
                                         neighbors.first, neighbors.second));
            } else if (neighbors.second == num_) {
                segment_iters_[neighbors] = max_bst_.emplace(
                    make_shared<Segment>(neighbors.second - 1 - neighbors.first,
                                         neighbors.second - 1, 
                                         neighbors.first, neighbors.second));
            } else {
                segment_iters_[neighbors] = max_bst_.emplace(
                    make_shared<Segment>((neighbors.second - neighbors.first) / 2,
                                         (neighbors.second - neighbors.first) / 2 + neighbors.first,
                                         neighbors.first, neighbors.second));
            }
            seats_[neighbors.first].second = neighbors.second;
            seats_[neighbors.second].first = neighbors.first;
        }
        
    private:
        struct Segment {
            int dis;
            int pos;
            int l;
            int r;
            Segment(int dis, int pos, int l, int r) : 
                dis(dis), pos(pos), l(l), r(r) {
            }
        };
        
        template <typename T>
        struct Compare {
            bool operator()(const T& a, const T& b) {
                return a->dis == b->dis ?
                    less<int>()(a->l, b->l) :
                    greater<int>()(a->dis, b->dis);
            }
        };
        
        template <typename T>
        struct PairHash {
            size_t operator()(const pair<T, T>& p) const {
                size_t seed = 0;
                seed ^= std::hash<T>{}(p.first)  + 0x9e3779b9 + (seed<<6) + (seed>>2);
                seed ^= std::hash<T>{}(p.second) + 0x9e3779b9 + (seed<<6) + (seed>>2);
                return seed;
            }
        };
        
        int num_;
        using S = shared_ptr<Segment>;
        multiset<S, Compare<S>> max_bst_;
        unordered_map<int, pair<int, int>> seats_;
        unordered_map<pair<int, int>, multiset<S, Compare<S>>::iterator, PairHash<int>> segment_iters_;
    };
    
    // Time:  seat:  O(logn) on average,
    //        leave: O(logn)
    // Space: O(n)
    class ExamRoom2 {
    public:
        ExamRoom2(int N) : num_(N) {
            max_bst_.emplace(make_shared<Segment>(num_, 0, -1, num_));
            seats_[-1] = make_pair(-1, num_);
            seats_[num_] = make_pair(-1, num_);
        }
        
        int seat() {
            while (!seats_.count((*max_bst_.cbegin())->l) ||
                   !seats_.count((*max_bst_.cbegin())->r) ||
                   seats_[(*max_bst_.cbegin())->l].second != (*max_bst_.cbegin())->r ||
                   seats_[(*max_bst_.cbegin())->r].first != (*max_bst_.cbegin())->l) {
                max_bst_.erase(max_bst_.begin());  // lazy deletion
            }
            
            const auto curr = *max_bst_.begin(); max_bst_.erase(max_bst_.begin());
            if (curr->l == -1 && curr->r == num_) {
                max_bst_.emplace(
                    make_shared<Segment>(curr->r - 1,
                                         curr->r - 1,
                                         curr->l + 1, curr->r));
            } else if (curr->l == -1) {
                max_bst_.emplace(
                    make_shared<Segment>(curr->r / 2,
                                         curr->r / 2,
                                         curr->l + 1, curr->r));
            } else if (curr->r == num_) {
                max_bst_.emplace(
                    make_shared<Segment>((curr->r - 1 - curr->l) / 2,
                                         (curr->r - 1 - curr->l) / 2 + curr->l,
                                         curr->l, curr->r - 1)); 
            } else {
                max_bst_.emplace(
                    make_shared<Segment>((curr->pos - curr->l) / 2,
                                         (curr->pos - curr->l) / 2 + curr->l,
                                         curr->l, curr->pos));
                max_bst_.emplace(
                    make_shared<Segment>((curr->r - curr->pos) / 2,
                                         (curr->r - curr->pos) / 2 + curr->pos,
                                         curr->pos, curr->r));
            }
            seats_[curr->pos] = make_pair(curr->l, curr->r);
            seats_[curr->l].second = curr->pos;
            seats_[curr->r].first = curr->pos;
            return curr->pos;
        }
        
        void leave(int p) {
            const auto neighbors = seats_[p];
            seats_.erase(p);
            if (neighbors.first == -1 && neighbors.second == num_) {
                max_bst_.emplace(
                    make_shared<Segment>(neighbors.second,
                                         neighbors.first + 1,
                                         neighbors.first, neighbors.second));
            } else if (neighbors.first == -1) {
                max_bst_.emplace(
                    make_shared<Segment>(neighbors.second,
                                         neighbors.first + 1,
                                         neighbors.first, neighbors.second));
            } else if (neighbors.second == num_) {
                max_bst_.emplace(
                    make_shared<Segment>(neighbors.second - 1 - neighbors.first,
                                         neighbors.second - 1,
                                         neighbors.first, neighbors.second));
            } else {
                max_bst_.emplace(
                    make_shared<Segment>((neighbors.second - neighbors.first) / 2,
                                         (neighbors.second - neighbors.first) / 2 + neighbors.first,
                                         neighbors.first, neighbors.second));
            }
            seats_[neighbors.first].second = neighbors.second;
            seats_[neighbors.second].first = neighbors.first;
        }
        
    private:
        struct Segment {
            int dis;
            int pos;
            int l;
            int r;
            Segment(int dis, int pos, int l, int r) : 
                dis(dis), pos(pos), l(l), r(r) {
            }
        };
        
        template <typename T>
        struct Compare {
            bool operator()(const T& a, const T& b) {
                return a->dis == b->dis ?
                    less<int>()(a->l, b->l) :
                    greater<int>()(a->dis, b->dis);
            }
        };
        
        int num_;
        using S = shared_ptr<Segment>;
        multiset<S, Compare<S>> max_bst_;
        unordered_map<int, pair<int, int>> seats_;
    };
    
    // Time:  seat:  O(logn) on average,
    //        leave: O(logn)
    // Space: O(n)
    class ExamRoom3 {
    public:
        ExamRoom3(int N) : num_(N) {
            max_heap_.emplace(make_shared<Segment>(num_, 0, -1, num_));
            seats_[-1] = make_pair(-1, num_);
            seats_[num_] = make_pair(-1, num_);
        }
        
        int seat() {
            while (!seats_.count(max_heap_.top()->l) ||
                   !seats_.count(max_heap_.top()->r) ||
                   seats_[max_heap_.top()->l].second != max_heap_.top()->r ||
                   seats_[max_heap_.top()->r].first != max_heap_.top()->l) {
                max_heap_.pop();  // lazy deletion
            }
            
            const auto curr = max_heap_.top(); max_heap_.pop();
            if (curr->l == -1 && curr->r == num_) {
                max_heap_.emplace(
                    make_shared<Segment>(curr->r - 1,
                                         curr->r - 1,
                                         curr->l + 1, curr->r));
            } else if (curr->l == -1) {
                max_heap_.emplace(
                    make_shared<Segment>(curr->r / 2,
                                         curr->r / 2,
                                         curr->l + 1, curr->r));
            } else if (curr->r == num_) {
                max_heap_.emplace(
                    make_shared<Segment>((curr->r - 1 - curr->l) / 2,
                                         (curr->r - 1 - curr->l) / 2 + curr->l,
                                         curr->l, curr->r - 1)); 
            } else {
                max_heap_.emplace(
                    make_shared<Segment>((curr->pos - curr->l) / 2,
                                         (curr->pos - curr->l) / 2 + curr->l,
                                         curr->l, curr->pos));
                max_heap_.emplace(
                    make_shared<Segment>((curr->r - curr->pos) / 2,
                                         (curr->r - curr->pos) / 2 + curr->pos,
                                         curr->pos, curr->r));
            }
            seats_[curr->pos] = make_pair(curr->l, curr->r);
            seats_[curr->l].second = curr->pos;
            seats_[curr->r].first = curr->pos;
            return curr->pos;
        }
        
        void leave(int p) {
            const auto neighbors = seats_[p];
            seats_.erase(p);
            if (neighbors.first == -1 && neighbors.second == num_) {
                max_heap_.emplace(
                    make_shared<Segment>(neighbors.second,
                                         neighbors.first + 1,
                                         neighbors.first, neighbors.second));
            } else if (neighbors.first == -1) {
                max_heap_.emplace(
                    make_shared<Segment>(neighbors.second,
                                         neighbors.first + 1,
                                         neighbors.first, neighbors.second));
            } else if (neighbors.second == num_) {
                max_heap_.emplace(
                    make_shared<Segment>(neighbors.second - 1 - neighbors.first,
                                         neighbors.second - 1,
                                         neighbors.first, neighbors.second));
            } else {
                max_heap_.emplace(
                    make_shared<Segment>((neighbors.second - neighbors.first) / 2,
                                         (neighbors.second - neighbors.first) / 2 + neighbors.first,
                                         neighbors.first, neighbors.second));
            }
            seats_[neighbors.first].second = neighbors.second;
            seats_[neighbors.second].first = neighbors.first;
        }
        
    private:
        struct Segment {
            int dis;
            int pos;
            int l;
            int r;
            Segment(int dis, int pos, int l, int r) : 
                dis(dis), pos(pos), l(l), r(r) {
            }
        };
        
        template <typename T>
        struct Compare {
            bool operator()(const T& a, const T& b) {
                return a->dis == b->dis ?
                    greater<int>()(a->l, b->l) :
                    less<int>()(a->dis, b->dis);
            }
        };
        
        int num_;
        using S = shared_ptr<Segment>;
        priority_queue<S, vector<S>, Compare<S>> max_heap_;
        unordered_map<int, pair<int, int>> seats_;
    };
    
    /**
     * Your ExamRoom object will be instantiated and called as such:
     * ExamRoom obj = new ExamRoom(N);
     * int param_1 = obj.seat();
     * obj.leave(p);
     */
    

      

    All LeetCode Questions List 题目汇总

  • 相关阅读:
    转:backbone.js源码解析:extend、Backbone.View
    转:前端单元测试总结
    转:JavaScript Promises相当酷:一种有趣的方案库
    npm发布模块
    转:nodejs npm常用命令
    nodejs守护进程forever
    转:SublimeText2 快捷键一览表
    转载7 Essential JavaScript Functions
    用node生成svg图片
    关于performance
  • 原文地址:https://www.cnblogs.com/lightwindy/p/9795789.html
Copyright © 2020-2023  润新知