Leetcode Google Tag

简书原创,转载请联系作者

// Longest Absolute File Path (Tricky)
// The input string "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"
// the longest absolute path is "dir/subdir2/subsubdir2/file2.ext", and its length is 32
// 用stack或者vector模拟layers
class Solution {
public:
    vector<string> split(string &s) {
        vector<string> res;
        stringstream ss(s);
        string str;
        while (getline(ss, str)) {
            res.push_back(str);
        }
        return res;
    }
    int lengthLongestPath(string input) {
        int max_len = 0;
        vector<int> level;
        for (string s : split(input)) {
            int cur_level = s.find_last_of('\t') + 1; // number of '\t's
            int cur_len = s.size() - cur_level + 1;
            if (cur_level != 0)
                cur_len += level[cur_level - 1];
            if (cur_level + 1 > level.size())
                level.push_back(cur_len);
            else
                level[cur_level] = cur_len;
            if (s.find('.') != -1)
                max_len = max(max_len, level[cur_level] - 1);
        }
        return max_len;
    }
};
// K Empty Slots (Tricky)
// flowers[i] = x means that the unique flower that blooms at day i will be at position x, where i and x will be in the range from 1 to N.
// Also given an integer k, you need to output in which day there exists two flowers in the status of blooming, and also the number of flowers between them is k and these flowers are not blooming.
// Solution 1: Use C++ ordered set O(nlogn)
// Search, removal, and insertion operations have logarithmic complexity. 
// Sets are usually implemented as red-black trees
// Insert the position into an ordered set day by day, then check the inserted flower’s neighbor to the left and right to see if they are k+1 positions-away from each other.
class Solution {
public:
    int kEmptySlots(vector<int>& flowers, int k) {
        set<int> positions;
        for (int day = 1; day <= flowers.size(); day++) {
            int pos = flowers[day - 1];
            // positions.insert(pos);
            // auto iter = positions.find(pos);
            auto iter = positions.insert(pos).first;
            if (iter != positions.begin()) {
                int left = *(--iter);
                if (pos - left == k + 1)
                    return day;
                iter++;
            }
            if (++iter != positions.end()) {
                int right = *iter;
                if (right - pos == k + 1)
                    return day;
            }
        }
        return -1;
    }
};
// Solution 2: Sliding Window O(n)
// The idea is to use an array days[] to record each position’s flower’s blooming day. 
// That means days[i] is the blooming day of the flower in position i+1. 
// We just need to find a subarray days[left, left+1,..., left+k, right] which satisfies: 
// for any i = left+1,..., left+k, we can have days[left] < days[i] && days[right] < days[i]. 
// Then, the result is max(days[left], days[right]).
class Solution {
public:
    int kEmptySlots(vector<int>& flowers, int k) {
        vector<int> days(flowers.size());
        for (int i = 0; i < flowers.size(); i++)
            days[flowers[i] - 1] = i + 1;
        int left = 0, right = k + 1, res = INT_MAX;
        for (int i = 1; right < flowers.size(); i++) {
            if (days[i] > days[left] && days[i] > days[right])
                continue;
            iLongest Substring with At Most K Distinct Charactersf (i == right)
                res = min(res, max(days[left], days[right]));
            left = i;
            right = i + k + 1;
        }
        return res == INT_MAX ? -1 : res;
    }
};
// Longest Substring with At Most K Distinct Characters
class Solution {
public:
    int lengthOfLongestSubstringKDistinct(string s, int k) {
        unordered_map<char, int> cache;
        int max_len = 0, start = 0, count = 0;
        for (int end = 0; end < s.size(); end++) {
            char c = s[end];
            if (!cache.count(c))
                count++;
            cache[c]++;
            while (count > k) { // count可以换成cache.size()
                cache[s[start]]--;
                if (cache[s[start]] == 0) {
                    cache.erase(s[start]);
                    count--;
                }
                start++;
            }
            max_len = max(max_len, end - start + 1);
        }
        return max_len;
    }
};
// Next Closest Time
// Given a time represented in the format "HH:MM", form the next closest time by reusing the current digits.
// Input: "19:34" Output: "19:39"
// Input: "23:59" Output: "22:22"
// Solution 1: Binary Search
class Solution {
public:
    string nextClosestTime(string time) {
        int hour = stoi(time.substr(0, 2));
        int minute = stoi(time.substr(3, 2));
        set<int> digits;
        digits.insert(time[0] - '0');
        digits.insert(time[1] - '0');
        digits.insert(time[3] - '0');
        digits.insert(time[4] - '0');
        vector<int> hours, minutes;
        for (int i : digits) {
            for (int j : digits) {
                int num = i * 10 + j;
                if (num <= 23)
                    hours.push_back(num);
                if (num <= 59)
                    minutes.push_back(num);
            }
        }
        sort(hours.begin(), hours.end());
        sort(minutes.begin(), minutes.end());
        // Find the first i which minutes[i] > minute
        int left = 0, right = minutes.size() - 1;
        while (left < right) {
            int mid = (left + right) / 2;
            if (minutes[mid] > minute)
                right = mid;
            else
                left = mid + 1;
        }
        if (minutes[left] > minute)
            return time.substr(0, 2) + ":" + (minutes[left] < 10 ? "0" : "") + to_string(minutes[left]);
        // Find the first i which hours[i] > hour
        left = 0, right = hours.size() - 1;
        while (left < right) {
            int mid = (left + right) / 2;
            if (hours[mid] > hour)
                right = mid;
            else
                left = mid + 1;
        }
        if (hours[left] > hour)
            return (hours[left] < 10 ? "0" : "") + to_string(hours[left]) + ":" + (minutes[0] < 10 ? "0" : "") + to_string(minutes[0]);
        else
            return (hours[0] < 10 ? "0" : "") + to_string(hours[0]) + ":" + (minutes[0] < 10 ? "0" : "") + to_string(minutes[0]);
    }
};
// Solution 2: Just turn the clock forwards one minute at a time until you reach a time with the original digits.
class Solution {
public:
    string nextClosestTime(string time) {
        int hour = stoi(time.substr(0, 2));
        int minute = stoi(time.substr(3, 2));
        set<int> digits;
        digits.insert(time[0] - '0');
        digits.insert(time[1] - '0');
        digits.insert(time[3] - '0');
        digits.insert(time[4] - '0');
        while (true) {
            minute += 1;
            if (minute == 60) {
                minute = 0;
                hour += 1;
                if (hour == 24)
                    hour = 0;
            }
            if (digits.count(minute % 10) && digits.count(minute / 10) && digits.count(hour % 10) && digits.count(hour / 10))
                return (hour < 10 ? "0" : "") + to_string(hour) + ":" + (minute < 10 ? "0" : "") + to_string(minute);
        }
    }
};
// License Key Formatting
// Given a number K, we would want to reformat the strings such that each group contains exactly K characters, except for the first group which could be shorter than K.
// Input: S = "2-5g-3-J", K = 2 Output: "2-5G-3J"
// Solution 1
class Solution {
public:
    string licenseKeyFormatting(string S, int K) {
        int count = 0;
        for (char c : S)
            if (c != '-')
                count++;
        int i = 0;
        string res = "";
        if (count == 0)
            return res;
        if (count % K != 0) {
            while (res.size() < count % K) {
                if (S[i] != '-') {
                    if (S[i] >= 'a' && S[i] <= 'z')
                        res += (S[i] + 'A' - 'a');
                    else
                        res += S[i];
                }
                i++;
            }
            res += '-';
        }
        while (i < S.size()) {
            int j = 0;
            while (i < S.size() && j < K) {
                if (S[i] != '-') {
                    if (S[i] >= 'a' && S[i] <= 'z')
                        res += (S[i] + 'A' - 'a');
                    else
                        res += S[i];
                    j++;
                }
                i++;
            }
            if (j == K) // Important!
                res += '-';
        }
        res.erase(res.size() - 1);
        return res;
    }
};
// Solution 2: Scan string backward
// Key observation: every (K+1)th character from the tail of the formatted string must be a '-'.
class Solution {
public:
    string licenseKeyFormatting(string S, int K) {
        string res;
        for (int i = S.size() - 1; i >= 0; i--) {
            if (S[i] != '-') {
                if (res.size() % (K + 1) == K)
                    res += '-';
                res += toupper(S[i]);
            }
        }
        reverse(res.begin(), res.end());
        return res;
    }
};
// Repeated String Match
// Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it. If no such solution, return -1.
// For example, with A = "abcd" and B = "cdabcdab". Return 3.
// Solution 1: Keep appending until the length A is greater or equal to B.
class Solution {
public:
    int repeatedStringMatch(string A, string B) {
        int n = A.size(), m = B.size();
        int k = ceil(m * 1.0 / n) + 1;
        string C = "";
        for (int i = 0; i < k; i++)
            C += A;
        if (C.find(B) == -1)
            return -1;
        return (C.find(B) >= n || C.find(B) + m <= (k - 1) * n) ? (k - 1) : k;
    }
};
class Solution {
public:
    int repeatedStringMatch(string A, string B) {
        int n = A.size(), m = B.size();
        int k = ceil(m * 1.0 / n);
        string C = "";
        for (int i = 0; i < k; i++)
            C += A;
        if (C.find(B) == -1) {
            C += A;
            return (C.find(B) == -1) ? -1 : k + 1;
        } else
            return k;
    }
};
// Moving Average from Data Stream
// Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window.
// For example,
// MovingAverage m = new MovingAverage(3);
// m.next(1) = 1
// m.next(10) = (1 + 10) / 2
// m.next(3) = (1 + 10 + 3) / 3
// m.next(5) = (10 + 3 + 5) / 3
class MovingAverage {
public:
    /** Initialize your data structure here. */
    MovingAverage(int size) {
        k = size;
        sum = 0;
    }
    
    double next(int val) {
        q.push(val);
        sum += val;
        if (q.size() > k) {
            sum -= q.front();
            q.pop();
        }
        return sum * 1.0 / q.size();
    }
private:
    queue<int> q;
    int k, sum;
};
/**
 * Your MovingAverage object will be instantiated and called as such:
 * MovingAverage obj = new MovingAverage(size);
 * double param_1 = obj.next(val);
*/
// Zigzag Iterator
// Given two 1d vectors, implement an iterator to return their elements alternately.
class ZigzagIterator {
public:
    ZigzagIterator(vector<int>& v1, vector<int>& v2) {
        if (!v1.empty())
            q.push(make_pair(v1.begin(), v1.end()));
        if (!v2.empty())
            q.push(make_pair(v2.begin(), v2.end()));
    }

    int next() {
        int res = *q.front().first;
        q.front().first++;
        if (q.front().first != q.front().second)
            q.push(q.front());
        q.pop();
        return res;
    }

    bool hasNext() {
        return !q.empty();
    }
private:
    queue<pair<vector<int>::iterator, vector<int>::iterator>> q;
};
/**
 * Your ZigzagIterator object will be instantiated and called as such:
 * ZigzagIterator i(v1, v2);
 * while (i.hasNext()) cout << i.next();
*/
// Binary Tree Longest Consecutive Sequence
// Given a binary tree, find the length of the longest consecutive sequence path along the parent-child connections.
class Solution {
public:
    int longestConsecutive(TreeNode* root) {
        int res = 0;
        longestConsecutive(root, INT_MAX, 0, res);
        return res;
    }
    void longestConsecutive(TreeNode* root, int parent, int path_len, int &res) {
        if (root == NULL)
            return;
        if (parent != INT_MAX && root->val == parent + 1)
            path_len++;
        else
            path_len = 1;
        res = max(res, path_len);
        longestConsecutive(root->left, root->val, path_len, res);
        longestConsecutive(root->right, root->val, path_len, res);
    }
};
// Sentence Screen Fitting (Tricky)
// Given a rows x cols screen and a sentence represented by a list of non-empty words, find how many times the given sentence can be fitted on the screen.
// 1. A word cannot be split into two lines.
// 2. The order of words in the sentence must remain unchanged.
// 3. Two consecutive words in a line must be separated by a single space.
// Time Limit Exceeded
class Solution {
public:
    int wordsTyping(vector<string>& sentence, int rows, int cols) {
        vector<int> length(sentence.size());
        int max_len = 0;
        for (int i = 0; i < sentence.size(); i++) {
            string word = sentence[i];
            max_len = max(max_len, (int)word.size());
            length[i] = word.size();
        }
        if (max_len > cols)
            return 0;
        int i = 0, j = 0, k = 0, res = 0;
        while (i < rows) {
            if (j + length[k] > cols) {
                i++;
                j = 0;
                continue;
            }
            j += (length[k++] + 1);
            if (k == sentence.size()) {
                res++;
                k = 0;
            }
        }
        return res;
    }
};
// C++ memorized search
// Use num to represent how many words can be put in the screen. 
// Use a map<i, cnt> to record for each line how many words cnt can be put when starting with word i. 
// So when we scan each line of the screen, we first get the starting word should be put on this line. 
// If this starting words is already in the map, then just read it; otherwise, create a new entry in this map.
class Solution {
public:
    int wordsTyping(vector<string>& sentence, int rows, int cols) {
        int num = 0, n = sentence.size();
        unordered_map<int, int> cache;
        for (int i = 0; i < rows; i++) {
            int start = num % n;
            if (!cache.count(start)) {
                int cnt = 0, j = 0, k = start;
                while (j + sentence[k].size() <= cols) {
                    j += (sentence[k++].size() + 1);
                    k %= n;
                    cnt++;
                }
                cache[start] = cnt;
            }
            num += cache[start];
        }
        return num / n;
    }
};
// Word Squares
// Given a set of words (without duplicates), find all word squares you can build from them.
// A sequence of words forms a valid word square if the kth row and column read the exact same string.
// All words will have the exact same length.
// Solution 1: Trie + DFS
class Solution {
public:
    class Trie {
        struct TrieNode {
            bool isWord;
            TrieNode* children[26];
            TrieNode() {
                isWord = false;
                for (int i = 0; i < 26; i++)
                    children[i] = NULL;
            }
        };
    public:
        Trie() {
            root = new TrieNode();
        }
        void insert(string word) {
            TrieNode *p = root;
            for (char c : word) {
                if (p->children[c - 'a'] == NULL)
                    p->children[c - 'a'] = new TrieNode();
                p = p->children[c - 'a'];
            }
            p->isWord = true;
        }
        vector<string> startsWith(string prefix) {
            TrieNode *p = root;
            for (char c : prefix) {
                p = p->children[c - 'a'];
                if (p == NULL)
                    return vector<string>();
            }
            vector<string> res;
            traversal(p, prefix, res);
            return res;
        }
    private:
        TrieNode *root;
        void traversal(TrieNode *t, string path, vector<string>& res) {
            if (t->isWord)
                res.push_back(path);
            for (int i = 0; i < 26; i++)
                if (t->children[i])
                    traversal(t->children[i], path + (char)('a' + i), res);
        }
    };
    vector<vector<string>> wordSquares(vector<string>& words) {
        if (words.empty())
            return vector<vector<string>>();
        const int n = words[0].size();
        Trie trie;
        for (string word : words)
            trie.insert(word);
        vector<string> square(n);
        vector<vector<string>> res;
        dfs(0, n, trie, square, res);
        return res;
    }
    void dfs(int k, const int n, Trie& trie, vector<string> square, vector<vector<string>>& res) {
        if (k == n) {
            res.push_back(square);
            return;
        }
        string prefix = square[k];
        for (string word : trie.startsWith(prefix)) {
            square[k] = word;
            for (int i = k + 1; i < n; i++)
                if (square[i].size() <= k)
                    square[i] += square[k][i];
                else
                    square[i][k] = square[k][i];
            dfs(k + 1, n, trie, square, res);
        }
    }
};
// Solution 2: Hash Table + DFS
// use unordered_map<string, vector<string>>
class Solution {
public:
    vector<vector<string>> wordSquares(vector<string>& words) {
        if (words.empty())
            return vector<vector<string>>();
        const int n = words[0].size();
        unordered_map<string, vector<string>> cache;
        for (string word : words)
            for (int i = 0; i < word.size(); i++)
                cache[word.substr(0, i)].push_back(word);
        vector<string> square(n);
        vector<vector<string>> res;
        dfs(0, n, cache, square, res);
        return res;
    }
    void dfs(int k, const int n, unordered_map<string, vector<string>>& cache, vector<string> square, vector<vector<string>>& res) {
        if (k == n) {
            res.push_back(square);
            return;
        }
        string prefix = "";
        for (int i = 0; i < k; i++)
            prefix += square[i][k];
        for (string word : cache[prefix]) {
            square[k] = word;
            dfs(k + 1, n, cache, square, res);
        }
    }    
};
// Range Sum Query 2D - Mutable (Tricky)
// Binary Indexed Tree 树状数组
class NumMatrix {
public:
    NumMatrix(vector<vector<int>> matrix) {
        n = matrix.size();
        m = n ? matrix[0].size() : 0;
        sums.resize(n + 1);
        for (int i = 0; i < n + 1; i++)
            sums[i].resize(m + 1);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                add(i, j, matrix[i][j]);
    }
    int sumRegion(int row1, int col1, int row2, int col2) {
        return sum(row2, col2) - sum(row2, col1 - 1) - sum(row1 - 1, col2) + sum(row1 - 1, col1 - 1);
    }
    void update(int row, int col, int val) {
        add(row, col, val - sumRegion(row, col, row, col));
    }
    
private:
    vector<vector<int>> sums;
    int n, m;
    
    void add(int row, int col, int val) {
        int i = row + 1, j;
        while (i < n + 1) {
            j = col + 1;
            while (j < m + 1) {
                sums[i][j] += val;
                j += (j & -j);
            }
            i += (i & -i);
        }
    }
    int sum(int row, int col) {
        int i = row + 1, j, res = 0;
        while (i) {
            j = col + 1;
            while (j) {
                res += sums[i][j];
                j -= (j & -j);
            }
            i -= (i & -i);
        }
        return res;
    }
};
// Bomb Enemy (Tricky)
// Given a 2D grid, each cell is either a wall 'W', an enemy 'E' or empty '0' (the number zero), return the maximum enemies you can kill using one bomb.
// The bomb kills all the enemies in the same row and column from the planted point until it hits the wall since the wall is too strong to be destroyed.
// Note that you can only put the bomb at an empty cell.
// Solution: We do simply two traversals. 
// One from upper left to bottom right, for each spot we compute enemies to its left and up including itself. 
// The other traversal is from bottom right to upper left, we compute enemies to its right and down and in the same time we add them up all to find the maxKill.
class Solution {
public:
    int maxKilledEnemies(vector<vector<char>>& grid) {
        if (grid.size() == 0 || grid[0].size() == 0)
            return 0;
        const int n = grid.size(), m = grid[0].size();
        vector<vector<int> > count(n, vector<int>(m, 0));
        vector<int> top(m, 0);
        for (int i = 0; i < n; i++) {
            int left = 0;
            for (int j = 0; j < m; j++) {
                count[i][j] = top[j] + left + (grid[i][j] == 'E');
                if (grid[i][j] == 'E') {
                    top[j]++;
                    left++;
                } else if (grid[i][j] == 'W') {
                    top[j] = 0;
                    left = 0;
                }    
            }
        }
        vector<int> bottom(m, 0);
        for (int i = n - 1; i >= 0; i--) {
            int right = 0;
            for (int j = m - 1; j >= 0; j--) {
                count[i][j] += (bottom[j] + right);
                if (grid[i][j] == 'E') {
                    bottom[j]++;
                    right++;
                } else if (grid[i][j] == 'W') {
                    bottom[j] = 0;
                    right = 0;
                }    
            }
        }
        int res = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                if (grid[i][j] == '0')
                    res = max(res, count[i][j]);
        return res;
    }
};
// UTF-8 Validation
// A character in UTF8 can be from 1 to 4 bytes long, subjected to the following rules:
// For 1-byte character, the first bit is a 0, followed by its unicode code.
// For n-bytes character, the first n-bits are all one's, the n+1 bit is 0, followed by n-1 bytes with most significant 2 bits being 10.
// Given an array of integers representing the data, return whether it is a valid utf-8 encoding.
// Note: The input is an array of integers. Only the least significant 8 bits of each integer is used to store the data. This means each integer represents only 1 byte of data.
class Solution {
public:
    bool validUtf8(vector<int>& data) {
        for (int i = 0; i < data.size(); i++) {
            int seq = data[i] & 0xFF;
            if ((seq >> 7) == 0) {
                continue;
            } else if ((seq >> 5) == 6) { // 110
                if (i + 1 >= data.size() || ((data[i + 1] & 0xFF) >> 6) != 2)
                    return false;
                i++;
            } else if ((seq >> 4) == 14) { // 1110
                if (i + 2 >= data.size() || ((data[i + 1] & 0xFF) >> 6) != 2 || ((data[i + 2] & 0xFF) >> 6) != 2)
                    return false;
                i += 2;
            } else if ((seq >> 3) == 30) { // 11110
                if (i + 3 >= data.size() || ((data[i + 1] & 0xFF) >> 6) != 2 || ((data[i + 2] & 0xFF) >> 6) != 2 || ((data[i + 3] & 0xFF) >> 6) != 2)
                    return false;
                i += 3;
            } else {
                return false;
            }
        }
        return true;
    }
};
// Decode String
// The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated exactly k times. 
// s = "3[a]2[bc]", return "aaabcbc".
// s = "3[a2[c]]", return "accaccacc".
class Solution {
public:
    string decodeString(string s) {
        string res;
        stack<pair<int, string>> brackets;
        int repeat = 0;
        for (char c : s) {
            if (c >= '0' && c <= '9') {
                repeat *= 10;
                repeat += (c - '0');
            } else if (c == '[') {
                brackets.push(make_pair(repeat, ""));
                repeat = 0;
            } else if (c == ']') {
                string cur = "";
                for (int i = 0; i < brackets.top().first; i++)
                    cur += brackets.top().second;
                brackets.pop();
                if (brackets.empty())
                    res += cur;
                else
                    brackets.top().second += cur;
            } else {
                if (brackets.empty())
                    res += c;
                else
                    brackets.top().second += c;
            }                
        }
        return res;
    }
};
// Plus One
// Given a non-negative integer represented as a non-empty array 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.
class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        if (digits.empty()) {
            digits.push_back(1);
            return digits;
        }
        int pos = digits.size() - 1;
        do {
            digits[pos]++;
            if (digits[pos] < 10)
                break;
            digits[pos] = 0;
            pos--;
        } while (pos >= 0);
        if (pos < 0)
            digits.insert(digits.begin(), 1);
        return digits;
    }
};
// Missing Ranges
// Given a sorted integer array where the range of elements are in the inclusive range [lower, upper], return its missing ranges.
// For example, given [0, 1, 3, 50, 75], lower = 0 and upper = 99, return ["2", "4->49", "51->74", "76->99"].
// Edge cases:
// [1,1,1]
// 1
// 1
// [-2147483648,-2147483648,0,2147483647,2147483647] 
// -2147483648
// 2147483647
// []
// 1
// 1
class Solution {
public:
    vector<string> findMissingRanges(vector<int>& nums, int lower, int upper) {
        vector<string> res;
        long long last = (long long)lower - 1;
        for (int num : nums) {
            if (num > last + 1)
                if (num == last + 2)
                    res.push_back(to_string(last + 1));
                else
                    res.push_back(to_string(last + 1) + "->" + to_string(num - 1));
            last = num;
        }
        if (last < upper)
            if (last == upper - 1)
                res.push_back(to_string(upper));
            else
                res.push_back(to_string(last + 1) + "->" + to_string(upper));
        return res;
    }
};
// Summary Ranges
// Given a sorted integer array without duplicates, return the summary of its ranges.
// Example:
// Input: [0,1,2,4,5,7]
// Output: ["0->2","4->5","7"]
class Solution {
public:
    vector<string> summaryRanges(vector<int>& nums) {
        vector<string> res;
        if (nums.empty())
            return res;
        int start = nums[0], last = nums[0];
        for (int i = 1; i < nums.size(); i++) {
            if (nums[i] > last + 1) {
                res.push_back(start == last ? to_string(start) : to_string(start) + "->" + to_string(last));
                start = nums[i];
            }
            last = nums[i];
        }
        res.push_back(start == last ? to_string(start) : to_string(start) + "->" + to_string(last));
        return res;
    }
};
// Android Unlock Patterns
// Given an Android 3x3 key lock screen and two integers m and n, where 1 ≤ m ≤ n ≤ 9, count the total number of unlock patterns of the Android lock screen, which consist of minimum of m keys and maximum n keys.
// Rules for a valid pattern:
// 1. Each pattern must connect at least m keys and at most n keys.
// 2. All the keys must be distinct.
// 3. If the line connecting two consecutive keys in the pattern passes through any other keys, the other keys must have previously selected in the pattern. No jumps through non selected key is allowed.
// 4. The order of keys used matters.
// Example: Given m = 1, n = 1, return 9.
class Solution {
public:
    int numberOfPatterns(int m, int n) {
        int res = 0;
        vector<vector<bool> > selected(3, vector<bool>(3, false));
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                dfs(0, i, j, m, n, selected, res);
        return res;
    }
    int distance(int x1, int y1, int x2, int y2) {
        return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
    }
    void dfs(int k, int i, int j, const int m, const int n, vector<vector<bool> > selected, int &res) {
        selected[i][j] = true;
        if (k + 1 >= m)
            res++;
        if (k + 1 == n)
            return;
        for (int ii = 0; ii < 3; ii++)
            for (int jj = 0; jj < 3; jj++)
                if (!selected[ii][jj]) {
                    int d = distance(i, j, ii, jj);
                    if (d == 1 || d == 2 || d == 5 || (d == 4 && selected[(i + ii) / 2][(j + jj) / 2]) || (d == 8 && selected[(i + ii) / 2][(j + jj) / 2]))
                        dfs(k + 1, ii, jj, m, n, selected, res);
                }
    }
};
// The optimization idea is that 1,3,7,9 are symmetric, 2,4,6,8 are also symmetric. 
// Hence we only calculate one among each group and multiply by 4.
int numberOfPatterns(int m, int n) {
    vector<vector<bool> > selected(3, vector<bool>(3, false));
    int res1 = 0, res2 = 0, res3 = 0;
    dfs(0, 0, 0, m, n, selected, res1);
    dfs(0, 0, 1, m, n, selected, res2);
    dfs(0, 1, 1, m, n, selected, res3);
    return res1 * 4 + res2 * 4 + res3;
}
// Encode and Decode Strings
// Design an algorithm to encode a list of strings to a string. The encoded string is then sent over the network and is decoded back to the original list of strings.
// Solution: The rule is, for each str in strs, encode it as <length> + ‘@’ + str
class Codec {
public:
    // Encodes a list of strings to a single string.
    string encode(vector<string>& strs) {
        string encoded = "";
        for (string &str: strs) {
            int len = str.size();
            encoded += to_string(len) + "@" + str;
        }
        return encoded;
    }

    // Decodes a single string to a list of strings.
    vector<string> decode(string s) {
        vector<string> r;
        int head = 0;
        while (head < s.size())    {
            int at_pos = s.find_first_of('@', head);
            int len = stoi(s.substr(head, at_pos - head));
            head = at_pos + 1;
            r.push_back(s.substr(head, len));
            head += len;
        }
        return r;
    }
};
// The Skyline Problem
struct Building {
    int left;
    int right;
    int height;
    Building(int l, int r, int h): left(l), right(r), height(h) {}
    bool operator <(const Building &other) const {
        if (left == other.left)
            return (height < other.height);
        return left > other.left;
        // Ensure next_left >= cur_left
        // Ensure if next_left == cur_left, then next_height < cur_height
    }
};
class Solution {
public:
    vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
        if (buildings.empty())
            return vector<pair<int, int>>();
        vector<pair<int, int>> result;
        priority_queue<Building> pq;
        for (int i = 0; i < buildings.size(); i++)
            pq.push(Building(buildings[i][0], buildings[i][1], buildings[i][2]));
        int cur_left = pq.top().left, cur_right = pq.top().right, cur_height = pq.top().height;
        pq.pop();
        while (!pq.empty()) {
            int next_left = pq.top().left, next_right = pq.top().right, next_height = pq.top().height;
            pq.pop();
            if (next_left > cur_right) {
                result.push_back(make_pair(cur_left, cur_height));
                result.push_back(make_pair(cur_right, 0));
                cur_left = next_left; cur_right = next_right; cur_height = next_height;
            } else if (next_left == cur_right) {
                if (next_height == cur_height) {
                    cur_right = next_right;
                } else {
                    result.push_back(make_pair(cur_left, cur_height));
                    cur_left = next_left; cur_right = next_right; cur_height = next_height;
                }
            } else if (next_left == cur_left) {
                if (next_right > cur_right)
                    pq.push(Building(cur_right, next_right, next_height));
            } else {
                // cur_left < next_left < cur_right
                if (next_height == cur_height) {
                    cur_right = max(cur_right, next_right);
                } else if (next_height < cur_height) {
                    if (next_right > cur_right)
                        pq.push(Building(cur_right, next_right, next_height));
                } else {
                    result.push_back(make_pair(cur_left, cur_height));
                    pq.push(Building(next_left, cur_right, cur_height));
                    cur_left = next_left; cur_right = next_right; cur_height = next_height;
                }
            }      
        }
        result.push_back(make_pair(cur_left, cur_height));
        result.push_back(make_pair(cur_right, 0));
        return result;
    }
};
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,442评论 25 707
  • 小灶四班最佳作品集结 一、开始时间:20180101 恭喜@林妖妖在1月1日的读书任务中获得最佳,...
    泉布阅读 935评论 0 0
  • 欢迎关注我的公众号:读书主义 更多精彩等着你! 这个读书方法,可能会颠覆你对读书以往的认知|开卷 或许读书已经成为...
    米米粒粒阅读 34,515评论 9 209
  • 以前,我有一盆文竹 虽然娇柔 但,生机蓬勃,绿意盎然 宛如心中的爱情 美好,令人幸福,神往。 有一天,我把它放在了...
    十五夜月阅读 513评论 0 4
  • Today is Thursday. I am going to read a new book, The Car...
    Mr_Oldman阅读 226评论 0 0