Analysis of Leetcode Problem Solving Ideas (35) 284-290

  1. Top Iterator
    Given an interface of an iterator class, the interface contains two methods: next() and hasNext(). Design and implement a top iterator that supports peek() operation-its essence is to peek() the elements that should be returned by the next() method.

A very boring question, nothing more than an advance test

/*
 * 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;
 *		Iterator(const vector<int>& nums);
 * 		Iterator(const Iterator& iter);
 *
 * 		// Returns the next element in the iteration.
 *		int next();
 *
 *		// Returns true if the iteration has more elements.
 *		bool hasNext() const;
 *	};
 */

class PeekingIterator : public Iterator {
    
    
    int nCurr;
    bool bEnd;
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.
	    bEnd = false;
        if (Iterator::hasNext()) 
        {
    
    
            nCurr = Iterator::next();
        } 
        else 
        {
    
    
            bEnd = true;
        }
	}

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

	// hasNext() and next() should behave the same as in the Iterator interface.
	// Override them if needed.
	int next() 
    {
    
    
        if (bEnd) 
        {
    
    
            return -1;
        }
        int res = nCurr;
	    if (Iterator::hasNext()) 
        {
    
    
            nCurr = Iterator::next();
        } 
        else 
        {
    
    
            bEnd = true;
        }
        return res;
	}

	bool hasNext() const 
    {
    
    
	    return !bEnd;
	}
};



  1. Finding repeated numbers
    Given an array nums containing n + 1 integers, whose numbers are all between 1 and n (including 1 and n), we know that there is at least one repeated integer. Assuming there is only one repeated integer, find the repeated number.

This question can be carried out by binary search or binary bit operation, but the best practice is to solve the problem with fast and slow pointers similar to 142. There are three key points here: 1. We use the array value as the next index item to build a graph. Due to repeated values, the graph must have a loop 2. Because the index starts from 0 and the value starts from 1, it is impossible for the fast and slow pointers to fall into an infinite loop when they start to loop. 3. After finding the number, loop again, the location where it meets is the access point of the loop, which is the value of the repeated element

class Solution {
    
    
public:
    int findDuplicate(vector<int>& nums) {
    
    
        int slow = 0, fast = 0;
        do {
    
    
            slow = nums[slow];
            fast = nums[nums[fast]];
        } while (slow != fast);
        slow = 0;
        while (slow != fast) {
    
    
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
};


  1. Game of Life
    According to the current state, write a function to calculate the next (after an update) state of all cells on the panel. The next state is formed by applying the above rules to each cell in the current state at the same time, where the birth and death of the cell occur simultaneously.

One pitfall in this question is that the modified may have an impact on the unmodified. If additional space is not applicable, the better way is to use additional marks, such as 0 for death, 1 for alive, increase by 2 for alive from death, -1 It means that from living to death can be solved perfectly

class Solution {
    
    
public:
    void gameOfLife(vector<vector<int>>& board) {
    
    
        int neighbors[3] = {
    
    0, 1, -1};

        int rows = board.size();
        int cols = board[0].size();

        // 遍历面板每一个格子里的细胞
        for (int row = 0; row < rows; row++) {
    
    
            for (int col = 0; col < cols; col++) {
    
    

                // 对于每一个细胞统计其八个相邻位置里的活细胞数量
                int liveNeighbors = 0;

                for (int i = 0; i < 3; i++) {
    
    
                    for (int j = 0; j < 3; j++) {
    
    

                        if (!(neighbors[i] == 0 && neighbors[j] == 0)) {
    
    
                            // 相邻位置的坐标
                            int r = (row + neighbors[i]);
                            int c = (col + neighbors[j]);

                            // 查看相邻的细胞是否是活细胞
                            if ((r < rows && r >= 0) && (c < cols && c >= 0) && (abs(board[r][c]) == 1)) {
    
    
                                liveNeighbors += 1;
                            }
                        }
                    }
                }

                // 规则 1 或规则 3 
                if ((board[row][col] == 1) && (liveNeighbors < 2 || liveNeighbors > 3)) {
    
    
                    // -1 代表这个细胞过去是活的现在死了
                    board[row][col] = -1;
                }
                // 规则 4
                if (board[row][col] == 0 && liveNeighbors == 3) {
    
    
                    // 2 代表这个细胞过去是死的现在活了
                    board[row][col] = 2;
                }
            }
        }

        // 遍历 board 得到一次更新后的状态
        for (int row = 0; row < rows; row++) {
    
    
            for (int col = 0; col < cols; col++) {
    
    
                if (board[row][col] > 0) {
    
    
                    board[row][col] = 1;
                } else {
    
    
                    board[row][col] = 0;
                }
            }
        }
    }
};

  1. Word law
    Given a pattern and a string str, judge whether str follows the same law.

1. Define two maps, why define two? Prevent [aaaa] and [cat dog dog cat], [abba] and [cat cat cat cat] from outputting true
2. Use stringstream to automatically output phrases
3. Judge :! (Ss >> s) Judge whether the pattern length is greater than str Length, and assign the string in the ss container to s
4. Judgment: (map.count© == 1 && map[c] != s) || (rmap.count(s) == 1 && rmap[s] != c)) to judge whether it matches
5. Judgment: (ss >> s)? false: true to judge whether the length of str is greater than the length of pattern

class Solution {
    
    
public:
    bool wordPattern(string pattern, string str) 
    {
    
    
        unordered_map<char, string> map;
        unordered_map<string, char> rmap;
        stringstream ss(str); string s;
        for(char c : pattern) 
        {
    
    
            if(!(ss >> s) || (map.count(c) == 1 && map[c] != s) 
                || (rmap.count(s) == 1 && rmap[s] != c)) 
                return false;
            map[c] = s; 
            rmap[s] = c;
        }
        return (ss >> s) ? false : true;
    }
};


  1. Nim game
    You and your friend, two people play Nim game together: There is a pile of rocks on the table, and each time you take turns to take 1-3 rocks. The one who removes the last stone is the winner. You act as the first mover.
    You are smart people, every step is the best solution. Write a function to determine whether you can win the game with a given number of stones.

When i must lose, i + 1, i + 2, i + 3 must win, so if i is a multiple of 4, it must lose, otherwise it must win

class Solution {
    
    
public:
    bool canWinNim(int n) {
    
    
        if (n <= 3)
            return true;
        return !(n % 4 == 0);
    }
};
  1. The median of the data stream
    Design a data structure that supports the following two operations:
    void addNum(int num)-Add an integer from the data stream to the data structure.
    double findMedian()-Returns the median of all current elements.

The easiest way is to save it in a dynamic array, and then sort it and then take the middle number every time you query. The optimized version is to insert in the sorted position every time you save, that is, you don't need to sort during query. A better method is to take two heaps: a smallest heap and a largest heap, so the top of the two heaps is the median. This approach needs to balance the two heaps, but the overall complexity is lower than that of the container. In addition, a self-balancing tree can also be used, which has similar effects.

class MedianFinder {
    
    
    priority_queue<int> lo;                              // max heap
    priority_queue<int, vector<int>, greater<int>> hi;   // min heap

public:
    // Adds a number into the data structure.
    void addNum(int num)
    {
    
    
        lo.push(num);                                    // Add to max heap

        hi.push(lo.top());                               // balancing step
        lo.pop();

        if (lo.size() < hi.size()) {
    
                         // maintain size property
            lo.push(hi.top());
            hi.pop();
        }
    }

    // Returns the median of current data stream
    double findMedian()
    {
    
    
        return lo.size() > hi.size() ? (double) lo.top() : (lo.top() + hi.top()) * 0.5;
    }
};


/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */
class MedianFinder {
    
    
    multiset<int> data;
    multiset<int>::iterator mid;

public:
    MedianFinder()
        : mid(data.end())
    {
    
    
    }

    void addNum(int num)
    {
    
    
        const int n = data.size();
        data.insert(num);

        if (!n)                                 // first element inserted
            mid = data.begin();
        else if (num < *mid)                    // median is decreased
            mid = (n & 1 ? mid : prev(mid));
        else                                    // median is increased
            mid = (n & 1 ? next(mid) : mid);
    }

    double findMedian()
    {
    
    
        const int n = data.size();
        return (*mid + *next(mid, n % 2 - 1)) * 0.5;
    }
};

  1. Serialization and deserialization of binary trees Serialization
    is the operation of converting a data structure or object into continuous bits, and then the converted data can be stored in a file or memory, and it can also be transmitted to another through the network In the computer environment, the original data is reconstructed in the opposite way.
    Please design an algorithm to realize the serialization and deserialization of the binary tree. The execution logic of your sequence/deserialization algorithm is not limited here, you only need to ensure that a binary tree can be serialized into a string and deserialize this string into the original tree structure.

Recursion or stack can be used. To put it bluntly, it is just traversing the binary tree in the first, middle and last order plus a string processing, there is no difficulty

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        string res;
        dfs_s(root, res);
        return res;
    }

    // 前序遍历序列转化为字符串
    void dfs_s(TreeNode* root, string& res) {
        if (!root) {
            res += "null ";
            return;
        }
        res += to_string(root->val) + ' ';
        dfs_s(root->left, res);
        dfs_s(root->right, res);
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        // 开始遍历索引
        int u = 0;
        return dfs_d(data, u);
    }

    TreeNode* dfs_d(string& data, int& u) {
        if (u >= data.size()) return NULL;
        if (data[u] == 'n') {
            u = u + 5;
            return NULL;
        }
        int val = 0, sign = 1;
        if (data[u] == '-') sign = -1, u ++ ;
        while(data[u] != ' '){val = val * 10 + data[u] - '0'; u++;}
        val *= sign;
        u = u + 1 ;

        auto root = new TreeNode(val);
        root->left = dfs_d(data, u);
        root->right = dfs_d(data, u);

        return root;
    }
};


// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));


Guess you like

Origin blog.csdn.net/u013354486/article/details/107700536