原创,转载请联系作者
// 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 split(string &s) {
vector 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 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& flowers, int k) {
set 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& flowers, int k) {
vector 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 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 digits;
digits.insert(time[0] - '0');
digits.insert(time[1] - '0');
digits.insert(time[3] - '0');
digits.insert(time[4] - '0');
vector 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 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 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& v1, vector& 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::iterator, vector::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& sentence, int rows, int cols) {
vector 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 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& sentence, int rows, int cols) {
int num = 0, n = sentence.size();
unordered_map 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 startsWith(string prefix) {
TrieNode *p = root;
for (char c : prefix) {
p = p->children[c - 'a'];
if (p == NULL)
return vector();
}
vector res;
traversal(p, prefix, res);
return res;
}
private:
TrieNode *root;
void traversal(TrieNode *t, string path, vector& 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> wordSquares(vector& words) {
if (words.empty())
return vector>();
const int n = words[0].size();
Trie trie;
for (string word : words)
trie.insert(word);
vector square(n);
vector> res;
dfs(0, n, trie, square, res);
return res;
}
void dfs(int k, const int n, Trie& trie, vector square, vector>& 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>
class Solution {
public:
vector> wordSquares(vector& words) {
if (words.empty())
return vector>();
const int n = words[0].size();
unordered_map> cache;
for (string word : words)
for (int i = 0; i < word.size(); i++)
cache[word.substr(0, i)].push_back(word);
vector square(n);
vector> res;
dfs(0, n, cache, square, res);
return res;
}
void dfs(int k, const int n, unordered_map>& cache, vector square, vector>& 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> 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> 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>& grid) {
if (grid.size() == 0 || grid[0].size() == 0)
return 0;
const int n = grid.size(), m = grid[0].size();
vector > count(n, vector(m, 0));
vector 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 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& 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> 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 plusOne(vector& 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 findMissingRanges(vector& nums, int lower, int upper) {
vector 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 summaryRanges(vector& nums) {
vector 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 > selected(3, vector(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 > 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 > selected(3, vector(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 + ‘@’ + str
class Codec {
public:
// Encodes a list of strings to a single string.
string encode(vector& 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 decode(string s) {
vector 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> getSkyline(vector>& buildings) {
if (buildings.empty())
return vector>();
vector> result;
priority_queue 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;
}
};