A.树木规划
只需要一遍扫过去,判断这个位置的值是否要移出,记录前一个没有移出的位置,从它们的距离中就能判断了。
class Solution {
public:
/**
* @param trees: the positions of trees.
* @param d: the minimum beautiful interval.
* @return: the minimum number of trees to remove to make trees beautiful.
*/
int treePlanning(vector<int> &trees, int d) {
int ans = 0,pr=trees[0];
for(int i=1;i<trees.size();i++)
{
if(trees[i] < pr + d)
{
ans++;continue;
}
pr = trees[i];
}
return ans;
}
};
B.正三角形拼接
1、如果有三个一样的那么答案就是0。
2、如果有两个一样的并且它们不是最长的,那么只要把一根长的切一段和它们一样的就可以了,答案就是1。
3、如果有一根的长度是另一根的两倍,那么把它对半切就可以了,答案就是1。(比赛没多想,我这里用了map)
4、其它情况就只能一刀切成一个。
class Solution {
public:
/**
* @param lengths: the lengths of sticks at the beginning.
* @return: return the minimum number of cuts.
*/
int makeEquilateralTriangle(vector<int> &lengths) {
int len = lengths.size();
map<int,int> mp;
sort(lengths.begin(),lengths.end());
int cnt = 1,c=-1,same=0,ok=0;
mp[lengths[0]] = 1;
for(int i=1;i<len;i++)
{
if(lengths[i]%2==0 && mp[lengths[i]/2])
ok = 1;
mp[lengths[i]] = 1;
if(lengths[i] == lengths[i-1])
cnt++;
else
cnt = 1;
if(same < cnt)
{
same = cnt;
c = i;
}
}
int ans;
if(same >=3 )
ans = 0;
else if(same == 2 &&c != len-1)
ans = 1;
else if(ok)
ans = 1;
else
ans = 2;
return ans;
}
};
C.大楼间穿梭
题目中说错了,操作一是跳到第一个不小于当前楼高的楼,搞了半天,比赛中即没修改题面也没有广播说题目错了。
每次都只能向后移动,明显DP,问题是如何进行操作一,我们只需要预处理出来当前楼后面第一个不比它矮的楼就可以了,怎么处理呢,也不难,只要搞了单调栈倒着处理就可以了。
class Solution {
public:
/**
* @param heights: the heights of buildings.
* @param k: the vision.
* @param x: the energy to spend of the first action.
* @param y: the energy to spend of the second action.
* @return: the minimal energy to spend.
*/
long long shuttleInBuildings(vector<int> &heights, int k, int x, int y) {
// write your code here.
const int maxn = 2e5+5;
int her[maxn];
int len = heights.size();
stack<int> st;
for(int i=len-1;i>=0;i--)
{
while(!st.empty())
{
if(heights[st.top()] < heights[i])
st.pop();
else
break;
}
if(!st.empty())
her[i] = st.top();
else
her[i] = i;
st.push(i);
}
long long dp[maxn];
for(int i=0;i<len;i++)
dp[i] = 1e18;
dp[0] = 0;
for(int i=0;i<len;i++)
{
if(her[i] <= i + k)
dp[her[i]] = min(dp[her[i]],dp[i] + x);
dp[i+1] = min(dp[i+1],dp[i] + y);
dp[i+2] = min(dp[i+2],dp[i] + y);
}
return dp[len - 1];
}
};
D.对称前后缀
区间DP,
f
[
i
,
j
]
f[i,j]
f[i,j]这个区间的最长对称前后缀。那么如果
s
[
i
]
!
=
s
[
j
]
s[i]!=s[j]
s[i]!=s[j]就是0,否则就是
f
[
i
+
1
,
j
−
1
]
+
1
f[i+1,j-1]+1
f[i+1,j−1]+1,不过要注意的是如果这是个回文串这样算就不对了,所以要特判下,如果
f
[
i
+
1
,
j
−
1
]
=
=
c
−
1
f[i+1,j-1] ==c-1
f[i+1,j−1]==c−1,那么它就是回文需要
+
2
+2
+2而不是
+
1
+1
+1。
class Solution {
public:
/**
* @param s: a string.
* @return: return the values of all the intervals.
*/
long long suffixQuery(string &s) {
// write your code here
long long f[3005][3005];
int len = s.size();
long long ans = 0;
for(int c=0;c<len;c++)//枚举区间长度
for(int i=0;i+c<len;i++)
{
if(c == 0)f[i][i] = 1;
else if(c == 1)f[i][i+1] = 2*(s[i]==s[i+1]);
else
{
if(s[i] == s[i+c])
{
if(f[i+1][i+c-1] == i+c-(i+1))//回文
f[i][i+c] = f[i+1][i+c-1] + 2;
else
f[i][i+c] = f[i+1][i+c-1] + 1;
}
else
f[i][i+c] = 0;
ans += f[i][i+c];
}
return ans;
}
};