LeetCode Contest #54
697. Degree of an Array
题目: 给定一个数组,定义这个数组的degree是数组中某一个数字出现次数的最大值。
degree of arr := max_i arr.count(arr[i])
求最短的一个continuous subarray,使得这个subarray的degree跟原数组相同。返回这个subarray的长度。
题解: 思路很简单,先把出现次数最多的数挑出来,然后看这些数在原数组中的“跨度”。
class Solution {
map<int, int> cnt, left, right;
/* left, right is used to record the*/
/* left most position and right most position*/
/* of a particular element.*/
public:
int findShortestSubArray(vector<int>& nums) {
for(int i=0;i<nums.size();++i){
cnt[nums[i]]++;
right[nums[i]] = i;
if(!left.count(nums[i])) left[nums[i]] = i;
}
int ans = nums.size(), max_cnt = 0;
for(auto p:cnt){
if(p.second == max_cnt)
ans = min(ans, right[p.first] - left[p.first] + 1);
else if(p.second > max_cnt){
max_cnt = p.second;
ans = right[p.first] - left[p.first] + 1;
}
}
return ans;
}
};
696. Count Binary Substrings
题目: 给定一个指包括0和1的string,让你从中挑出满足以下条件的substring:
- 0跟1的个数相同
- 0都group together,1也都group together
也就是这种形式的substring:11…100…0或00…011…1,且其中1,0个数相等。
求这种substring的总数。
题解: 思路很简单,先把groups of continuous 1和0全提出来,然后这样的substring肯定出现在相邻的groups里面,个数就是min(#group1, #group0)。比如111跟0000相临,那满足条件的substring只可能是10, 1100, 111000,它们的个数就是1的个数,因为1比0少。
class Solution {
inline char flip(char c){return c=='1'? '0':'1';}
/* input '1' return '0', input '0' return '1';*/
public:
int countBinarySubstrings(string s) {
int ans = 0;
for(auto i=s.find(s[0]); i<s.size() && i!=string::npos ;){
auto j = s.find(flip(s[i]),i);
if(j == string::npos) return ans;
auto k = s.find(s[i], j);
if(k == string::npos) k = s.size();
ans += min(int(j-i), int(k-j));
i = j;
}
return ans;
}
};
698. Partition to K Equal Sum Subsets
题目: 给定一个数组,数组长度不超过16(也就是说规模很小),然后让你判断是否可以把这个数组分成k个groups,使得每个group的和相等。
题解: 其实是暴力,(反正我是这么做的,如果有人有更好的方法,非常欢迎提出来。)因为规模不大。
- 首先如果这个数组的sum不能被k整除,就不用考虑了。
- 如果可以整除,我的做法是分两步:
- 先求所有的group使得每个group的和是sum/k,用dfs
- 每一个group用一个二进制数表示,这样后面的操作容易些。
- 看这些groups能不能挑出k两个不相交的,还是用dfs
- 两个dfs都没超时,也是挺不容易的。
- 上面做法,有个地方要注意一下:判断两个group是否相交的时候,如果用(group1 & group2) == 0括号不能省啊。开始就是由于这个原因,我debug的时候半天不知道错在哪儿,后来索性改成!(group1 & group2)。
class Solution {
vector<int> A, G;
void dfs1(int cur, int i, int target){
if(target == 0){
G.push_back(cur);
return;
}
for(int j=i;j<A.size();++j) if(target>=A[j]){
dfs1(cur|(1<<j), j+1, target-A[j]);
}
}
bool dfs2(int cur, int rest){
if(!rest) return true;
for(auto s:G) if(!(s&cur) && dfs2(cur|s, rest-1)) return true;
return false;
}
public:
bool canPartitionKSubsets(vector<int>& nums, int k) {
A.assign(nums.begin(),nums.end());
int sum = 0;
for(auto n:nums) sum+=n;
if(!sum || k<=1) return true;
if( sum%k ) return false;
dfs1(0, 0, sum/k);
return dfs2(0, k-1);
}
};
699. Falling Squares
题目: 其实就是模拟俄罗斯方块,而且每个方块都是正方形。一系列方块由一个pair的数组给出,且对于每一个pair,第一个元素是正方形left edge的位置,第二个元素是边长。方块依次落下,要求输出一个数组,每个元素对应每一个方块落下之后的最大高度。
题解: 用一个map(sorted)来标记现有每个线段的高度:map<int, int> H,这样H[pos]表示pos右边的高度。知道碰到下一个比pos大,而且也在H中的元素,也就是高度改变的点。初始的时候令H[0] = H[2E8] = 0,其实是方便以后操作;然后每次加入一个方块后,更新这个H即可,不难写:
class Solution {
map<int, int> H;
int upd(const pair<int, int> &S){
/*return the final height of the current falling square*/
int l = S.first, h = S.second, r = S.first + S.second;
auto it1 = --H.upper_bound(l), it2 = --H.upper_bound(r);
int max_H = h + it1->second, tail_H = it2->second;
++it1;
while(it1!=H.end() && it1->first < r){
max_H = max(max_H, h + it1->second);
it1 = H.erase(it1);
}
H[r] = tail_H;
return H[l] = max_H;
}
public:
vector<int> fallingSquares(vector<pair<int, int>>& positions) {
vector<int> ans;
H[0] = H[2E8] = 0;
int cur = 0;
for(auto S:positions) ans.push_back(cur = max(cur, upd(S)));
return ans;
}
};