第一部分,编号500以内的部分
第二部分,编号501-1000部分
本博客不再更新,后面的部分见我写的另一个博客 myblog
这是编号1000以上的部分(加锁部分暂时买不起,后面有机会开个会员)
- Grid Illumination
题意:给定一个N,表示有N*N的网格(下标0到N-1),网格中有一些点放置有灯。每个灯能够照亮所在的行列以及两条对角线。
给定一些查询,每个查询是一个点,首先先确定位置是否被照亮,如果是,那么周围3*3方格内的灯都灭掉。接着查询下一个。
需要返回每个查询位置是否被照亮,保存为一个数组
题解:首先用一个set保存灯所在的点,接着我们可以保存被照亮的行,列和两个对角线,行和列直接用坐标就可以表示。而对角线我们取它和x轴的交点,分别是x - y 和x + y。接着就是在上面做查询和删除操作了。
class Solution {
static const int MOD = 100007;
struct pair_hash {
inline size_t operator()(const pair<int,int> & p) const {
return (p.first % MOD * 1000 + p.second) % MOD;
}
};
public:
vector<int> gridIllumination(int N, vector<vector<int>>& lamps, vector<vector<int>>& queries) {
unordered_set<pair<int, int>, pair_hash> lamps_pos;
unordered_map<int, int> ill_pos[4];
for(int i = 0;i < lamps.size(); ++i){
int x = lamps[i][0], y = lamps[i][1];
lamps_pos.insert(make_pair(x, y));
++ill_pos[0][x];
++ill_pos[1][y];
++ill_pos[2][x - y];
++ill_pos[3][x + y];
}
vector<int> ans;
for(int i = 0;i < queries.size(); ++i){
int x = queries[i][0], y = queries[i][1];
if(ill_pos[0][x] || ill_pos[1][y] || ill_pos[2][x - y] || ill_pos[3][x + y])
ans.push_back(1);
else
ans.push_back(0);
for(int j = -1; j <= 1; ++j){
for(int k = -1; k <= 1; ++k){
int cur_x = x + j;
int cur_y = y + k;
if(cur_x < 0 || cur_y < 0 || cur_x >= N || cur_y >= N) continue;
if(lamps_pos.count(make_pair(cur_x, cur_y))){
lamps_pos.erase(make_pair(cur_x, cur_y));
--ill_pos[0][cur_x];
--ill_pos[1][cur_y];
--ill_pos[2][cur_x - cur_y];
--ill_pos[3][cur_x + cur_y];
}
}
}
}
return ans;
}
};
- Numbers With Repeated Digits
题意:给定一个数字N,问不大于N的正整数有多少个里面具有重复数字的
题解:重复的难求,我们求不重复的,然后总数N + 1个减去不重复的
不重复的我们可以通过逐位计算。不过有另外的解法,稍慢一点,就是动态规划,见代码注释。
int dp[10][1024];
class Solution {
public:
int numDupDigitsAtMostN(int N) {
if (N < 10) return 0;
string str = to_string(N);
int numDigits = str.length();
memset(dp, -1, sizeof dp);
return N - helper(0, 0, 1, str) + 1;
}
//dp[index][d]表示index位的数,位标记为d的不重复数字数目
//helper计算的是不超过N的有多少
//tight表示前缀固定,和N的前缀一样
int helper(int index, int d, int tight, string& str)
{
if (index == str.length()) return 1;
if (tight != 1 && dp[index][d] != -1) return dp[index][d];
int res = 0;
int range = tight == 1 ? str[index] - '0' : 9;
for (int i = 0 ; i <= range; i++)
{
if (d & (1 << i)) continue;
int newTight = 0;
if (tight == 1 && (str[index] - '0') == i) newTight = 1;
//前导0不能做标记,因为可以重复出现
if (d == 0 && i == 0) res += helper(index + 1, d, newTight, str);
else res += helper(index + 1, d | (1 << i), newTight, str);
}
if (!tight) dp[index][d] = res;
return res;
}
};
- Camelcase Matching
搞错了,这是个中等题,难怪这么简单。
题意:给定一些query串和一个pattern。一个query串能和pattern匹配如果pattern能够通过插入一些小写字母得到query串。
返回一个bool数组,表示每个query是否和pattern匹配
题解:贪心匹配。每个query如果能匹配完pattern,且其他字符都是小写字母就算匹配成功。
class Solution {
public:
vector<bool> camelMatch(vector<string>& queries, string pattern) {
vector<bool> ans;
for(int i = 0;i < queries.size(); ++i){
string &cur_q = queries[i];
int pos = 0;
int match = true;
for(int j = 0; j < cur_q.length(); ++j){
if(pos < pattern.length() && cur_q[j] == pattern[pos]){
++pos;
continue;
}
if('a' <= cur_q[j] && cur_q[j] <= 'z') continue;
match = false;
break;
}
ans.push_back(match && pos == pattern.size());
}
return ans;
}
};
- Stream of Characters
题意:给定一些words(字符串),构造一个数据结构可以支持一下查询。每次查询一个字符。如果倒数k(k>=1)个查询的字符组成的字符串在words中出现,则返回true,否则返回false
题解:几乎是AC自动机的模板题。构建AC自动机。记录到当前字符为止,匹配的最长位置。然后如果当前位置是一个单词结尾返回true,否则如果last指针指向的位置不是0,则说明有后缀可以匹配到字符串,返回true。
当然,用逆序字符串构建Trie也可以过。
class AAM{
static const int N = 300000;
int ch[N][26];
int fail[N],last[N],vis[N];
bool val[N];
int cnt,root;
int p; //当前到达的节点(最长匹配)
public:
void init(){
cnt = 0, p = root = cnt++;
memset(vis,0,sizeof(vis));
memset(ch[0],0,sizeof(ch[0]));
memset(val,0,sizeof(val));
}
void insert(string s){
int len = s.length();
int p = root;
for(int i = 0; i < len; ++i){
int index = s[i] - 'a';
if(!ch[p][index]){
memset(ch[cnt],0,sizeof(ch[cnt]));
ch[p][index] = cnt++;
}
p = ch[p][index];
}
val[p] = true;
}
void getfail(){
int p = root;
queue<int>Q;
fail[p] = last[p] = p;
for(int i = 0;i < 26; ++i){
int u = ch[p][i];
if(u) {
last[u] = fail[u] = p;Q.push(u);}
else ch[p][i] = p;
}
while(!Q.empty()){
int p = Q.front(); Q.pop();
for(int i = 0; i < 26; ++i){
int &u = ch[p][i];
if(u) {
fail[u] = ch[fail[p]][i];
last[u] = val[fail[u]]?fail[u]:last[fail[u]];
Q.push(u);
}else u = ch[fail[p]][i];
}
}
}
bool find(char c){
p = ch[p][c - 'a'];
return val[p] || last[p];
}
};
class StreamChecker {
AAM ac_m;
public:
StreamChecker(vector<string>& words) {
ac_m.init();
for(int i = 0;i < words.size(); ++i)
ac_m.insert(words[i]);
ac_m.getfail();
}
bool query(char letter) {
return ac_m.find(letter);
}
};
/**
* Your StreamChecker object will be instantiated and called as such:
* StreamChecker* obj = new StreamChecker(words);
* bool param_1 = obj->query(letter)
*/
- Recover a Tree From Preorder Traversal
题意:给定一个字符串,表示一颗二叉树的前序遍历顺序,如下例,其中数字是节点值,横杠表示深度。而且如果一个节点只有一个儿子,那么必定是左儿子。
例子
Input: “1-2–3--4-5–6--7”
Output: [1,2,5,3,4,6,7]
题解:用一个栈恢复遍历过程即可。
/**
* 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 {
int get_val(const string &s, int &pos){
int val = 0;
while(pos < s.size() && isdigit(s[pos])) {
val = val * 10 + s[pos] - '0';
++pos;
}
return val;
}
int get_depth(const string &s, int &pos){
int depth = 0;
while(pos < s.size() && s[pos] == '-') {
++depth;
++pos;
}
return depth;
}
public:
TreeNode* recoverFromPreorder(string s) {
stack<pair<TreeNode*, int> > st;
TreeNode *root = nullptr;
int pos = 0;
root = new TreeNode(get_val(s, pos));
st.push(make_pair(root, 0));
while(pos < s.size()){
int depth = get_depth(s, pos);
int val = get_val(s, pos);
TreeNode* cur = new TreeNode(val);
TreeNode* top = st.top().first;
int pre_depth = st.top().second;
if(pre_depth + 1 == depth){
top->left = cur;
}else{
while(pre_depth + 1 != depth){
st.pop();
top = st.top().first;
pre_depth = st.top().second;
}
top->right = cur;
st.pop();
}
st.push(make_pair(cur, depth));
}
return root;
}
};
- Escape a Large Maze
题意:在一个 1 0 6 × 1 0 6 10^6\times10^6 106×106的棋盘上(索引从0到 1 0 6 − 1 10^6 - 1 106−1),有一些障碍点(blocked最多200个),给定一个source和target两个点,问source能不能每次走上下左右四个方向到达target。
题解:如果不是棋盘这么大,直接BFS就能求解。稍微想一想就知道,这么少的障碍点,实际上大部分都是能通过的,我们可以将障碍点网里缩,而不改变source和target的连通性。具体做法就是将x坐标和y坐标重新布局索引。
直观的想象一下,如果不同的块之间有大于1的缝存在,我们只需要让这个缝等于1就可以了。
我们可以分别考虑x和y。考虑x的情况,先排序,如果有0,那么保持0,不然的话下标从1开始(把下方压缩为一行的空间)。
如果当前的x和前一个一样,那么保持相同的索引,如果比前面多一,那么保持多一。如果多二及以上,那么我们把它们的距离缩小到2,也就是索引加2。y同理。这样缩小得到的问题棋盘不会多于400 * 400。
题的数据有缺陷,标程也是:输入数据
[[99999,99998],[99998,99999]]
[0,0]
[99999,99999]
答案应该是false而标准程序给出的是true,并且数据中没有这样的例子。
这个和样例
[[0,1],[1,0]]
[0,0]
[1,1]
是一样的,只不过一个右上角,一个左下角。
class Solution {
public:
int re_idx(vector<int> &xy_loc, map<int,int> &xy_map){
int idx = 1;
//边界触及0
if(xy_loc[0] == 0) idx = 0;
xy_map[xy_loc[0]] = idx;
for(int i = 1;i < xy_loc.size(); ++i){
if(xy_loc[i] == xy_loc[i - 1]) continue;
if(xy_loc[i] == xy_loc[i - 1] + 1) xy_map[xy_loc[i]] = ++idx;
else xy_map[xy_loc[i]] = (idx += 2);
}
//边界触及99999
if(*xy_loc.rbegin() == 99999) return idx;
return idx + 1;
}
bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
map<int,int> x_map, y_map;
vector<int> x_loc, y_loc;
x_loc.push_back(source[0]);
x_loc.push_back(target[0]);
y_loc.push_back(source[1]);
y_loc.push_back(target[1]);
for(int i = 0;i < blocked.size(); ++i){
x_loc.push_back(blocked[i][0]);
y_loc.push_back(blocked[i][1]);
}
int idx_x = 1, idx_y = 1;
sort(x_loc.begin(), x_loc.end());
sort(y_loc.begin(), y_loc.end());
int x_max = re_idx(x_loc, x_map);
int y_max = re_idx(y_loc, y_map);
bool vis[x_max + 1][y_max + 1];
memset(vis, 0, sizeof(vis));
source[0] = x_map[source[0]];
target[0] = x_map[target[0]];
source[1] = y_map[source[1]];
target[1] = y_map[target[1]];
for(int i = 0;i < blocked.size(); ++i){
int x = x_map[blocked[i][0]];
int y = y_map[blocked[i][1]];
vis[x][y] = true;
}
int x_dir[] = {
1, 0, -1, 0};
int y_dir[] = {
0, 1, 0, -1};
cout<<source[0]<<source[1]<<endl;
cout<<target[0]<<target[1]<<endl;
cout<<x_max<<y_max<<endl;
queue<pair<int,int>> Q;
Q.push(make_pair(source[0], source[1]));
vis[source[0]][source[1]] = true;
while(!Q.empty()){
pair<int,int> u = Q.front(); Q.pop();
int x = u.first, y = u.second;
if(x == target[0] && y == target[1]) return true;
for(int i = 0;i < 4; ++i){
int next_x = x + x_dir[i];
int next_y = y + y_dir[i];
if(next_x < 0 || next_y < 0 || next_x > x_max || next_y > y_max || vis[next_x][next_y]) continue;
vis[next_x][next_y] = true;
Q.push(make_pair(next_x, next_y));
}
}
return false;
}
};
- Longest Duplicate Substring
题意;给定一个字符串,求里面最长的重复子串(出现2次或以上)。
题解:
解法1,二分答案+Rabin-Carp就是二分长度,然后滚动hash判断是否重复。
解法2,问题实际上就是求所有后缀的最长公共前缀,可以用后缀数组做法
下面是后缀数组代码
class Solution {
static const int maxn = 1e5 + 2;
int wa[maxn], wb[maxn], wv[maxn], ws[maxn], sa[maxn], height[maxn], *rank;
int cmp(int *r, int a, int b, int l, int n){
if(r[a] != r[b]) return false;
if(a + l >= n && b + l >= n) return true;
if(a + l >= n || b + l >= n) return false;
return r[a + l] == r[b + l];
}
//待排序的字符串放在r数组中,从r[0]到r[n-1],长度为n,且最大值小于m
//sa是我们要求的后缀数组
//这里x数组保存的值相当于是rank值。下面的操作只是用x数组来比较字符的大小,所以没有必要求出当前真实的rank值。所以这里x保存位置i的字符就好
//后面的x才是rank值,x[i]=后缀i的名次
int* cal_suffix_arr(int *r, int *sa, int n, int m){
int *x = wa,*y = wb;
memset(ws, 0, m * sizeof(int));
//对第一个字符排序
for(int i = 0;i < n; ++i) ++ws[x[i] = r[i]];
for(int i = 1;i < m; ++i) ws[i] += ws[i - 1];
for(int i = n - 1; i >=0; --i) sa[--ws[x[i]]] = i;
//对长度为2^j的后缀排序
for(int j = 1, p = 0; p < n; j*=2, m = p){
p = 0;
//接下来进行若干次基数排序,在实现的时候,这里有一个小优化。基数排序要分两次,第一次是对第二关键字排序,
//第二次是对第一关键字排序。对第二关键字排序的结果实际上可以利用上一次求得的sa直接算出,没有必要再算一次。
//数组y保存的是对第二关键字排序的结果,y[p]= 排名为p的为哪个后缀的第二关键字
//因为从n - j开始后面的第二部分都是空串,所以排在前面
for(int i = n - j; i < n; ++i) y[p++] = i;
for(int i = 0; i < n; ++i) if(sa[i] >= j) y[p++] = sa[i] - j;
//wv[i] = x[y[i]]是第二关键字排名为i的后缀的第一关键字排名
//基数排序。按第二关键字排序后,第一关键字的原排名。用第一关键字分桶就得到了一二关键字的排序
//ws是m个桶
for(int i = 0; i < n; ++i) wv[i] = x[y[i]];
for(int i = 0; i < m; ++i) ws[i] = 0;
//分桶,排序
for(int i = 0; i < n; ++i) ++ws[wv[i]]; //++ws[x[i]]也一样
for(int i = 1; i < m; ++i) ws[i] += ws[i - 1];
for(int i = n - 1; i >= 0; --i) sa[--ws[wv[i]]] = y[i];
//求解新的rank数组x
//根据sa求rank。sa[i]是排名为i的后缀,rank[sa[i]]后缀sa[i]的排名
//因为这里的sa数组对于后缀相同时,排名按位置前后排,所以这里rank还需要判重
//对于两个后缀sa[i - 1]和sa[i],他们第一关键字和第二关键字是否都一样,这个可以通过判断本来的rank在对应位置是否相同
swap(x, y); x[sa[0]]=0; p = 1;
for(int i = 1; i < n; ++i){
x[sa[i]] = cmp(y, sa[i - 1], sa[i], j, n) ? p - 1: p++;
}
}
return x;
}
void cal_height(int n, int *sa, int *rank, int *r, int *height) {
// vector<int> rank(n);
// for(int i = 0; i < n; ++i)rank[sa[i]] = i;
int k = 0;
for(int i = 0; i < n; ++i){
int cur = rank[i];
if(cur == 0) {
height[cur] = 0;
k = 0;
} else {
if(k > 0) --k;
int j = sa[cur-1];
while(i + k < n && j + k < n && r[i + k] == r[j + k]) ++k;
height[cur] = k;
}
}
}
public:
string longestDupSubstring(string S) {
int n = S.size(), m = 26;
int *s = new int[n];
for(int i = 0;i < n; ++i){
s[i] = S[i] - 'a';
}
rank = cal_suffix_arr(s, sa, n, m);
cal_height(n, sa, rank, s, height);
int max_len = 0, pos = 0;
for(int i = 1;i < n; ++i){
if(height[i] > max_len){
max_len = height[i];
pos = sa[i];
}
}
delete []s;
return S.substr(pos, max_len);
return "";
}
};
- Number of Submatrices That Sum to Target
题意:给定一个至多300*300的整数矩阵,和一个target,问有多少子矩阵的和为target
题解:做过最大矩阵和的应该很容易想到,这个用前缀和以及HashMap可以使得复杂度为O(N^3)。
具体的就是先求矩阵前缀和。然后枚举上下边,变成一维问题。
也就是给定一个数组,求和为target的子段有多少?
有了前缀和,枚举每个位置i,前缀和为pre_sum[i],就是找前面有多少个j使得pre_sum[i] - pre_sum[j] = target
转化一下,就是求i前面的前缀和有多少个等于pre_sum[i] - target。这个可以用一个map来保存计数。
class Solution {
public:
int numSubmatrixSumTarget(vector<vector<int>>& matrix, int target) {
int n = matrix.size(), m = matrix[0].size();
vector<vector<int>> pre_sum(n + 1, vector<int>(m + 1, 0));
for(int i = 1;i <= n; ++i)
for(int j = 1; j <= m; ++j)
pre_sum[i][j] = pre_sum[i - 1][j] + pre_sum[i][j - 1] + matrix[i - 1][j - 1] - pre_sum[i - 1][j - 1];
unordered_map<int,int> pre_sum_catch;
int ans = 0;
for(int i = 1; i <= n; ++i)
for(int j = i; j <= n; ++j){
pre_sum_catch.clear();
pre_sum_catch[0] = 1;
for(int k = 1; k <= m; ++k){
int p = pre_sum[j][k] - pre_sum[i - 1][k];
ans += pre_sum_catch[p - target];
++pre_sum_catch[p];
}
}
return ans;
}
};
- Shortest Common Supersequence
题意:给定两个字符串,求一个最短的字符串能将这两个串作为子序列
题解:动态规划。dp[i][j]表示将str1的前缀i和str2的前缀j作为子序列的串的最短长度。
则当前串的最短长度的串,考虑最后一个字符,首先它必须等于str1[i]或者str2[j]
如果str1[i] == str2[j] 那么最后一个字符和他们都相等,则同时考虑它们两个不会产生更差的结果(就是贪心),转化为子问题,dp[i][j] = dp[i - 1][j - 1] + 1
如果不相等,那么考虑最后一个字符的两种情况取最优。
class Solution {
public:
string shortestCommonSupersequence(string str1, string str2) {
int n = str1.length(), m = str2.length();
int dp[n + 1][m + 1];
//init
for(int i = 0;i <= n; ++i) dp[i][0] = i;
for(int j = 0;j <= m; ++j) dp[0][j] = j;
for(int i = 1;i <= n; ++i){
for(int j = 1;j <= m; ++j){
if(str1[i - 1] == str2[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1;
}
}
vector<char> s;
int cur_i = n, cur_j = m;
//回溯答案
for(int k = 0; k < dp[n][m]; ++k){
if(cur_i > 0 && cur_j > 0 && str1[cur_i - 1] == str2[cur_j - 1]){
s.push_back(str1[cur_i - 1]);
--cur_i; --cur_j;
}else{
if(cur_i > 0 && dp[cur_i - 1][cur_j] + 1 == dp[cur_i][cur_j]){
s.push_back(str1[cur_i - 1]);
--cur_i;
}else{
s.push_back(str2[cur_j - 1]);
--cur_j;
}
}
}
return string(s.rbegin(), s.rend());
}
};
- Find in Mountain Array
题意:交互题。一个数组称为MountainArray,如果它的长度至少位3,且存在一个0<i<len - 1使得0到i递增,i到len - 1递减
题解:不能直接操作数组,要通过一个类获取第k个值。先找出最大值所在的下标。通过二分搜索得到,然后先搜索前半段,再搜索后半段即可。
/**
* // This is the MountainArray's API interface.
* // You should not implement it, or speculate about its implementation
* class MountainArray {
* public:
* int get(int index);
* int length();
* };
*/
class Solution {
public:
int findInMountainArray(int target, MountainArray &mountainArr) {
int n = mountainArr.length();
int left = 0, right = n - 1, peak_idx;
while(left <= right){
int mid = (left + right) / 2;
int mid_num = mountainArr.get(mid);
if(mountainArr.get(mid + 1) < mid_num){
right = mid - 1;
}else
left = mid + 1;
}
peak_idx = right + 1;
left = 0; right = peak_idx;
while(left <= right){
int mid = (left + right) / 2;
int mid_num = mountainArr.get(mid);
if(mid_num <= target){
left = mid + 1;
}else
right = mid - 1;
}
if(left > 0 && mountainArr.get(--left) == target) return left;
left = peak_idx + 1; right = n - 1;
while(left <= right){
int mid = (left + right) / 2;
int mid_num = mountainArr.get(mid);
if(mid_num >= target){
left = mid + 1;
}else
right = mid - 1;
}
if(mountainArr.get(--left) == target) return left;
return -1;
}
};
- Brace Expansion II
题意:给定一个表达式,形式如 “{ {a,z},a{b,c},{ab,z}}”,其中大括号表示可选内容。{a,z}表示a或者z,a{b,c}表示ab或者ac。所以前面的串能表示的有[“a”,“ab”,“ac”,“z”]
给定一个大括号表达式, 问这个串能表示哪些串,按字典序返回。
题解:采用递归,分解成子问题解决。比较难搞的一个模拟题。写的比较挫。
首先如果整个串被一个大括号包含,那么答案就是每个逗号分隔部分答案的并
如果不被括号包围,那么就是各部分答案的笛卡尔积
class Solution {
//判断是否被一个大括号包围整个串
bool check_split(string expression){
int brace_num = 0;
if(*expression.rbegin() != '}' or *expression.begin() != '{') return false;
for(int i = 0;i < expression.length() - 1; ++i){
if(expression[i] == '{') ++brace_num;
else if(expression[i] == '}') --brace_num;
if(brace_num == 0) return false;
}
return true;
}
//将串按照逗号分隔为子串
vector<string> split(string expression){
vector<string> vs;
for(int i = 1; i < expression.size() - 1; ++i){
int j = i + 1;
int brace_num = (expression[i] == '{');
while(j < expression.size() - 1 and (expression[j] != ',' or brace_num != 0)){
switch(expression[j++]){
case '}': --brace_num; break;
case '{': ++brace_num; break;
}
}
vs.push_back(expression.substr(i, j - i));
i = j;
}
return vs;
}
//计算笛卡尔积
vector<string> merge_strs(vector<vector<string>> &vs){
vector<string> v(1,"");
for(int i = 0;i < vs.size(); ++i){
vector<string> t;
for(int j = 0;j < v.size(); ++j){
for(int k = 0;k < vs[i].size(); ++k){
t.push_back(v[j] + vs[i][k]);
}
}
v.swap(t);
}
sort_and_remove_duplicate(v);
return v;
}
//排序,去重
void sort_and_remove_duplicate(vector<string> &v){
sort(v.begin(), v.end());
int pos = 0;
for(int i = 0;i < v.size(); ++i){
if(i < v.size() - 1 and v[i] == v[i + 1] ) continue;
v[pos++] = v[i];
}
v.resize(pos);
}
public:
vector<string> braceExpansionII(string expression) {
vector<string> vs;
string substr = "";
int brace_count = 0;
//分两种情况
if(check_split(expression)){
vector<string> strs = split(expression);
for(int i = 0;i < strs.size(); ++i){
vector<string> t = braceExpansionII(strs[i]);
vs.insert(vs.end(), t.begin(), t.end());
}
sort_and_remove_duplicate(vs);
return vs;
}
vector<vector<string> >substrs;
for(int i = 0;i < expression.size(); ++i){
int j = i + 1;
if(expression[i] == '{'){
int brace_num = 0;
while(expression[j] != '}' or brace_num != 0){
switch(expression[j++]){
case '}': --brace_num; break;
case '{': ++brace_num; break;
}
}
substrs.push_back(braceExpansionII(expression.substr(i, j - i + 1)));
//字母
}else{
j = i;
while(j + 1 < expression.size() and expression[j + 1] != '{') ++j;
substrs.push_back(vector<string>(1, expression.substr(i, j - i + 1)));
}
i = j;
}
return merge_strs(substrs);
}
};
- Parsing A Boolean Expression
题意:给定一个真值表达式,包函数字符{’(’, ‘)’, ‘&’, ‘|’, ‘!’, ‘t’, ‘f’, ‘,’},求表达式的真值。
例如
Input: expression = “|(&(t,f,t),!(t))”
Output: false
题解:采用栈的方式进行计算,遇到有括号时,计算栈顶部分的表达式,所有表达式都计算完。因为没有空格,且都是合法的表达式,所以比较简单。
class Solution {
bool is_opt(char e){
return e == '&' || e == '|' || e == '!' || e == ' ';
}
public:
bool parseBoolExpr(string expression) {
stack<char> s;
stack<bool> val;
char opt;
bool cur_val;
for(int i = 0;i < expression.size(); ++i){
//碰到运算符,因为不存在空格,所以直接可以continue了
//而且表达式都有括号,所以在遇到左括号时push,不然的话在遇到运算符就可push了
if(is_opt(expression[i]) || expression[i] == ',') continue;
//非运算符
//左括号
if(expression[i] == '('){
if(i > 0 && is_opt(expression[i - 1])) s.push(expression[i - 1]);
else s.push(' ');
//右括号
}else if(expression[i] == ')'){
while(!is_opt(s.top())){
val.push(s.top() == 't');
s.pop();
}
opt = s.top(); s.pop();
cur_val = (opt == '&');
while(!val.empty()){
switch(opt){
case ' ' : cur_val = val.top(); break;
case '|': cur_val |= val.top(); break;
case '&': cur_val &= val.top(); break;
case '!': cur_val = !val.top(); break;
}
val.pop();
}
if(cur_val) s.push('t');
else s.push('f');
// expression[i] == 't'或者'f'
}else{
s.push(expression[i]);
}
}
return s.top() == 't';
}
};
- Longest Chunked Palindrome Decomposition
题意:给定一个字符串text。问最多能把它分成多少个子串,text=(a_1, a_2,…,a_k)使得a_i = a_{k + 1 - i}
题解:贪心。贪心做分割。假设前缀a能和后缀a匹配,如果存在一个前缀包含a,假设为a b,能和后缀匹配。那么在a这里分割比在b处分割更好。
证明: 设前缀[a, c, b] 和后缀[a, a, c] 或者[a,c,a]匹配(分别对应的情况是[a c] 和末尾的[a c]或者[a]和末尾的[a]匹配,其中len(a) == len(b)),(中括号表示拼接,c可以为空串)。
- 情形1: [ a , c , b ] [a,c,b] [a,c,b]和 [ a , a , c ] [a,a,c] [a,a,c]匹配。则有 [ c , b ] =