Wednesday, September 30, 2020

L 362. Design Hit Counter --------M

Design a hit counter which counts the number of hits received in the past 5 minutes.

Each function accepts a timestamp parameter (in seconds granularity) and you may assume that calls are being made to the system in chronological order (ie, the timestamp is monotonically increasing). You may assume that the earliest timestamp starts at 1.

It is possible that several hits arrive roughly at the same time.

Example:

HitCounter counter = new HitCounter();

// hit at timestamp 1.
counter.hit(1);

// hit at timestamp 2.
counter.hit(2);

// hit at timestamp 3.
counter.hit(3);

// get hits at timestamp 4, should return 3.
counter.getHits(4);

// hit at timestamp 300.
counter.hit(300);

// get hits at timestamp 300, should return 4.
counter.getHits(300);

// get hits at timestamp 301, should return 3.
counter.getHits(301); 

Follow up:

What if the number of hits per second could be very large? Does your design scale? 


A:

就是加一个sliding window log.

class HitCounter {
public:
    /** Initialize your data structure here. */
    HitCounter() {
        
    }
    
    /** Record a hit.
        @param timestamp - The current timestamp (in seconds granularity). */
    void hit(int timestamp) {
        record.push_back(timestamp);
        if(record.size() >= max_capacity){
            vector<int> newV;
            while(curIndex < record.size()){
                newV.push_back(record[curIndex++]);
            }
            curIndex=0;
            record = newV;
        }
    }
    
    /** Return the number of hits in the past 5 minutes.
        @param timestamp - The current timestamp (in seconds granularity). */
    int getHits(int timestamp) {
        while(curIndex< record.size() && (timestamp - record[curIndex]) >= 300){
            curIndex++;
        }
        return record.size() - curIndex;
    }
private:
    vector<int> record;
    int max_capacity = 10000;
    int curIndex = 0;
};

/**
 * Your HitCounter object will be instantiated and called as such:
 * HitCounter* obj = new HitCounter();
 * obj->hit(timestamp);
 * int param_2 = obj->getHits(timestamp);
 */



L 281. Zigzag Iterator ----M ~~~~!!!!

 Given two 1d vectors, implement an iterator to return their elements alternately.

 

Example:

Input:
v1 = [1,2]
v2 = [3,4,5,6] 
Output: [1,3,2,4,5,6]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,3,2,4,5,6].

 

Follow up:

What if you are given k 1d vectors? How well can your code be extended to such cases?

Clarification for the follow up question:
The "Zigzag" order is not clearly defined and is ambiguous for k > 2 cases. If "Zigzag" does not look right to you, replace "Zigzag" with "Cyclic". For example:

Input:
[1,2,3]
[4,5,6,7]
[8,9]

Output: [1,4,8,2,5,9,3,6,7].

A:

这里,最先错的地方,就是 iterator, 不需要拷贝原有内容的。

这个比较傻逼。是因为自己以前没有看过真正的代码实现。

class ZigzagIterator {
public:
    ZigzagIterator(vector<int>& v1, vector<int>& v2) {
        s1 = v1.begin();
        s2 = v2.begin();
        e1 = v1.end();
        e2 = v2.end();
        isFirst = true;        
    }

    int next() {        
        int res=0;
        if(s1==e1){
            res = *s2;
            s2++;
        }else if(s2==e2){
            res = *s1;
            s1++;
        }else{
            if(isFirst){                
                res = *s1;
                isFirst = ! isFirst;
                s1++;
            }else{
                res = *s2;
                isFirst = ! isFirst;
                s2++;
            }
        }
        return res;
    }

    bool hasNext() {
        return s1 !=e1 ||  s2 != e2;
    }
private:
    vector<int>::iterator s1,s2,e1,e2;
    bool isFirst;
};

/**
 * Your ZigzagIterator object will be instantiated and called as such:
 * ZigzagIterator i(v1, v2);
 * while (i.hasNext()) cout << i.next();
 */






L 280. Wiggle Sort ---M ~~~~可以允许直接两两交换

 Given an unsorted array nums, reorder it in-place such that nums[0] <= nums[1] >= nums[2] <= nums[3]....

Example:

Input: nums = [3,5,2,1,6,4]
Output: One possible answer is [3,5,1,6,2,4]

A:


-------先来个 构造法 --------  排序,然后每2个位置,互换

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int n = nums.size();
        for(int i = 1;i+1<n;i+=2){
            //swich i, and i+1 position
            int tmp = nums[i];
            nums[i] = nums[i+1];
            nums[i+1] = tmp;
        }        
    }
};

然而上面的代码明显不是最优的。

考虑到我们允许  ==   因此可以直接反复交换

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        int tmp=0;
        for(int i = 0; i+1 < nums.size(); i++){
            if(i&1){// position 1,3,5...
                if(nums[i] < nums[i+1]){
                    //swich i, and i+1 position
                    tmp = nums[i];
                    nums[i] = nums[i+1];
                    nums[i+1] = tmp;
                }
            }else{ // position 0 2,4,6,8
                if(nums[i] > nums[i+1]){
                    //swich i, and i+1 position
                    tmp = nums[i];
                    nums[i] = nums[i+1];
                    nums[i+1] = tmp;
                }
            }
        }        
    }
};



L 286. Walls and Gates --------M

You are given a m x n 2D grid initialized with these three possible values.

  1. -1 - A wall or an obstacle.
  2. 0 - A gate.
  3. INF - Infinity means an empty room. We use the value 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647.

Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled with INF.

Example: 

Given the 2D grid:

INF  -1  0  INF
INF INF INF  -1
INF  -1 INF  -1
  0  -1 INF INF

After running your function, the 2D grid should be:

  3  -1   0   1
  2   2   1  -1
  1  -1   2  -1 

0 -1 3 4 

A:

                 就是基本的BFS 
class Solution {
public:
    void wallsAndGates(vector<vector<int>>& rooms) {
        int m = rooms.size();
        if(m==0)
            return;
        int n = rooms[0].size();
        vector<pair<int, int>> preLevel;
        for(int i =0;i<m;i++){
            for(int j = 0;j<n;j++){
                if(rooms[i][j]==0){
                    preLevel.push_back(make_pair(i,j));
                }
            }
        }
        vector<pair<int,int>> diff{{1,0},{-1,0},{0,1},{0,-1}};
        int depth = 0;
        while(not preLevel.empty()){
            vector<pair<int, int>> curLevel;
            depth++;
            for(auto &it : preLevel){
                for(auto & d : diff){
                    int x = it.first + d.first;
                    int y = it.second + d.second;
                    if(x>=0 && x < m && y >=0 && y <n && rooms[x][y]==INT_MAX ){
                        rooms[x][y] = depth;
                        curLevel.push_back(make_pair(x,y));
                    }
                }
            }
            preLevel = curLevel;
        }
    }
};


L 276. Paint Fence ------E

There is a fence with n posts, each post can be painted with one of the k colors.

You have to paint all the posts such that no more than two adjacent fence posts have the same color.

Return the total number of ways you can paint the fence.

Note:
n and k are non-negative integers.

Example:

Input: n = 3, k = 2
Output: 6
Explanation: Take c1 as color 1, c2 as color 2. All possible ways are:

            post1  post2  post3      
 -----      -----  -----  -----       
   1         c1     c1     c2 
   2         c1     c2     c1 
   3         c1     c2     c2 
   4         c2     c1     c1  
   5         c2     c1     c2 

  6 c2 c2 c1 

A:

DP  

             想出来     递推公式   

If n > 2, then the result can be derived by appending 2 posts with the same color that is different from the last one to the result of n-2 and appending 1 post with a color that's different from the last one to the result of n-1.


class Solution {
public:
    int numWays(int n, int k) {
        if(n == 0 || k == 0)
            return 0;
        vector<int> sameAsLast(n,0);
        vector<int> diffAsLast(n,0);
        diffAsLast[0] = k;
        for(int i = 1;i<n;i++){
            sameAsLast[i] = diffAsLast[i-1];
            diffAsLast[i] = (k-1)*( sameAsLast[i-1] + diffAsLast[i-1]);
        }
        return sameAsLast[n-1] + diffAsLast[n-1];
    }
};




L 285.Inorder Successor in BST -------M

 Given a binary search tree and a node in it, find the in-order successor of that node in the BST.

The successor of a node p is the node with the smallest key greater than p.val.

 

Example 1:

Input: root = [2,1,3], p = 1
Output: 2
Explanation: 1's in-order successor node is 2. Note that both p and the return value is of TreeNode type.

Example 2:

Input: root = [5,3,6,2,4,null,null,1], p = 6
Output: null
Explanation: There is no in-order successor of the current node, so the answer is null.

 

Note:

  1. If the given node has no in-order successor in the tree, return null.
  2. It's guaranteed that the values of the tree are unique.


A:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        if(not root or not p)
            return nullptr;
        if(root->val <= p->val){
            return inorderSuccessor(root->right, p);
        }else{
            auto tmp = inorderSuccessor(root->left, p);
            if(tmp){
                return tmp;
            }else{
                return root;
            }
        }
    }
};



L 370. Range Addition ----------M ~~~~~第二种方法

Assume you have an array of length n initialized with all 0's and are given k update operations.

Each operation is represented as a triplet: [startIndex, endIndex, inc] which increments each element of subarray A[startIndex ... endIndex] (startIndex and endIndex inclusive) with inc.

Return the modified array after all k operations were executed.

Example:

Input: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
Output: [-2,0,3,5,3]

Explanation:

Initial state:
[0,0,0,0,0]

After applying operation [1,3,2]:
[0,2,2,2,0]

After applying operation [2,4,3]:
[0,2,5,5,3]

After applying operation [0,2,-2]: 

[-2,0,3,5,3] 


A:

这个考虑到可能有多个重复区间,因此,我们不能简单地sort一下就够。

需要用heap , 每次去除最前面的两个interval, 然后对比并merge

class Solution {
public:
    vector<int> getModifiedArray(int length, vector<vector<int>>& updates) {
        auto compare = [](const vector<int> &a, const vector<int> &b){
            if(a[0]==b[0]){
                return a[1] > b[1];
            }else{
                return a[0] > b[0];
            }
        };
        priority_queue<vector<int>,vector<vector<int>>, decltype(compare)> minQ(compare);        
        for(auto & t : updates){
            minQ.push(t);
        }
        vector<int> res(length,0);
        while(not minQ.empty()){
            auto start = minQ.top(); //CANNOT use auto &, otherwise, start[] cannot be assigned
            minQ.pop();
            if(minQ.empty()){
                updateRange(res, start[0], start[1], start[2]);
                break;
            }
            auto end = minQ.top();
            minQ.pop();
            if(start[1] < end[0]){ // two disjoint set
                updateRange(res, start[0], start[1], start[2]);
                minQ.push(end);
            }else if( end[1] <= start[1]  ){
                updateRange(res, start[0], end[0]-1, start[2]);
                updateRange(res, end[0], end[1], start[2]+end[2]);
                start[0] = end[1]+1;
                minQ.push(start);
            }else{ // start[1] < end[1]                
                updateRange(res, start[0], end[0]-1, start[2]);
                updateRange(res, end[0], start[1], start[2] + end[2]);
                end[0] = start[1]+1;
                minQ.push(end);
            }
        }        
        return res;
    }
private:
    void updateRange(vector<int> & res, int start, int end, int val){
        for(int i =start; i<= end;i++){
            res[i] += val;
        }
    }
};


错误,就是一开始用了sort().  然而那样是不够的。

**********************方法二 ***********

很巧妙的方法,  每次在interval的开始放上 增加的值。 并在结束位置的下一个,放上其相应的负值。    最终在结果上,从前往后加起来即可

class Solution {
public:
    vector<int> getModifiedArray(int length, vector<vector<int>>& updates) {
        vector<int> res(length, 0);
        for(auto & t : updates){
            res[t[0]] += t[2];
            if(t[1]+1<length)
                res[t[1]+1] -= t[2];
        }
        for(int i =1;i<length;i++){
            res[i] += res[i-1];
        }
        return res;
    }
};






Monday, September 28, 2020

658. Find K Closest Elements ---M ~~~

Given a sorted array arr, two integers k and x, find the k closest elements to x in the array. The result should also be sorted in ascending order. If there is a tie, the smaller elements are always preferred.

 

Example 1:

Input: arr = [1,2,3,4,5], k = 4, x = 3
Output: [1,2,3,4]

Example 2:

Input: arr = [1,2,3,4,5], k = 4, x = -1
Output: [1,2,3,4]

 

Constraints:

  • 1 <= k <= arr.length
  • 1 <= arr.length <= 10^4
  • Absolute value of elements in the array and x will not exceed 104

 


A:

先找到比 <= x  的最大值, 假设在index  seed。  然后再看看比seed+1 的difference 是否更小。

最后再linearly probe till length k

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        int n = arr.size();
        // binary search to find index with bigger value that's <= than x
        int start = 0, end = n-1;
        while(start < end){
            int mid = start + (end - start)/2;
            if(arr[mid]>x){
                end = mid-1;
            }else{ // start = mid, but could cause infinite loop, thus 
                if(arr[mid+1]> x){
                    end = mid;
                }else{
                    start = mid+1;
                }
            }            
        }        
        int seed = start;
        // chec that it is possible that's next is closer
        if(seed+1 < n && abs(arr[seed+1]-x) < abs(arr[seed]-x)){
            seed = seed+1;
        }
        // now linear probe to search.
        start = seed;
        end = seed;
        while(end - start +1 < k){
            if(end==n-1){
                start--;
            }else if(start ==0){
                end++;
            }else{
                long absLeft = abs(long(arr[start-1]) - x);
                long absRight = abs(long(arr[end+1]) - x);
                if(absLeft <= absRight){
                    start--;
                }else{
                    end++;
                }
            }
        }
        vector<int> res(arr.begin()+start, arr.begin()+end+1);
        return res;
    }
};


错误是:

1:   在start = mid 的时候,没有考虑,if mid == start, 就会有infinite loop

2:   在while loop中,一开始,画蛇添足。加了别的停止条件了。 哎。人生啊




L 369. Plus One Linked List ----M

 Given a non-negative integer represented as non-empty a singly linked list of digits, plus one to the integer.

You may assume the integer do not contain any leading zero, except the number 0 itself.

The digits are stored such that the most significant digit is at the head of the list.

Example :

Input: [1,2,3]
Output: [1,2,4]


A:

核心技巧就是加了一个 dummy header, 然后递归调用

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* plusOne(ListNode* head) {
        ListNode * dummy = new ListNode(0);
        dummy->next = head;
        
        helper(dummy);
        if(dummy->val == 1){            
            return dummy;
        }else{
            delete dummy;
            return head;
        }
    }
private:
    bool helper(ListNode* head){
        if(not head->next){
            int carry = (head->val + 1) /10;
            head->val = (head->val + 1) % 10;
            return carry ==1;
        }else{
            bool hasCarry = helper(head->next);
            if(hasCarry){                
                int carry = (head->val + 1) /10;
                head->val = (head->val + 1) % 10;
                return carry ==1;                
            }else{
                return false;
            }
        }        
    }
};




L 366. Find Leaves of Binary Tree --------M

Given a binary tree, collect a tree's nodes as if you were doing this: Collect and remove all leaves, repeat until the tree is empty.

 

Example:

Input: [1,2,3,4,5]
  
          1
         / \
        2   3
       / \     
      4   5    

Output: [[4,5,3],[2],[1]]

 

Explanation:

1. Removing the leaves [4,5,3] would result in this tree:

          1
         / 
        2          

 

2. Now removing the leaf [2] would result in this tree:

          1          

 

3. Now removing the leaf [1] would result in the empty tree:

          []         
[[3,5,4],[2],[1]], [[3,4,5],[2],[1]], etc, are also consider correct answers since per each level it doesn't matter the order on which elements are returned.

A:

就是简单的递归,然后返回 到 leaf 的距离

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> findLeaves(TreeNode* root) {
        vector<vector<int>> res;
        helper(root, res);
        return res;
    }
private:
    int helper(TreeNode* root, vector<vector<int>>& res ){ // return depth to lowest leaf
        if(not root)
            return -1;
        int l = helper(root->left, res);
        int r = helper(root->right, res);
        int level = max(l, r)+1;
        if(res.size() < level + 1){
            res.push_back(vector<int>());
        }
        res[level].push_back(root->val);
        return level;
    }   
};

Mistakes:

level 没有+1



Sunday, September 27, 2020

L 294. Flip Game II -------------M

You are playing the following Flip Game with your friend: Given a string that contains only these two characters: + and -, you and your friend take turns to flip two consecutive "++" into "--". The game ends when a person can no longer make a move and therefore the other person will be the winner.

Write a function to determine if the starting player can guarantee a win.

Example:

Input: s = "++++"
Output: true 
Explanation: The starting player can guarantee a win by flipping the middle "++" to become "+--+".

Follow up:

Derive your algorithm's runtime complexity. 


A:

 典型的backtrack

每次更改2个位置,然后看剩下的是不是怎么变化也赢不了。

class Solution {
public:
    bool canWin(string s) {
        return helper(s);
    }
private:
    bool helper(string &s){
        for(int i =0;i+1<s.length();i++){
            if(s[i]=='+' && s[i+1]=='+'){
                s[i]=s[i+1] = '-';
                if(not helper(s)){
                    s[i]=s[i+1] = '+';//put back  Also need put back
                    return true;
                }
                s[i]=s[i+1] = '+';//put back
            }
        }
        return false;
    }
};

Mistakes:
上面的 写成  for(int i =0;i<s.length() -1 ;i++)  就会不对, 仔细想想为什么。  对于"" 的输入。


***************method 2*******************
数出 ++ 的个数。 分别计算
如果是2,3.只能一个move。 如果是4, first Player可以选择留给1个还是0个。