一、1103. Distribute Candies to People
一道简单题,不用多说,适合刚学编程的朋友做。
按着看完题目后的常规思路,一个人一个人分配糖果就好。
class Solution {
public:
vector<int> distributeCandies(int candies, int n) {
vector<int> ans(n,0);
//m=每次要分配的糖果数;have=总共已经分配了的糖果数;p=当前要分配糖果给谁
int m=1,p=0,have=0;
while(candies>have)
{
if(m+have>=candies)
{
ans[p]+=candies-have;
break;
}
ans[p]+=m;
have+=m++;
p=(p+1)%n;
}
return ans;
}
};
二、1104. Path In Zigzag Labelled Binary Tree
这题难度为easy,给定一棵按照一定规则排列的满二叉树(除最后一层无任何子节点外,每一层上的所有结点都有两个子节点的二叉树):
- 在奇数行(即,第一行、第三行、第五行……)中,按从左到右的顺序对节点进行标记
- 在偶数行(即,第二行、第四行、第六行……)中,按从右到左的顺序对节点进行标记
- 节点的标记从1开始。
给出一个节点的标签,求从根到这个节点经过哪些节点。
思路:
结合满二叉树的性质,若节点的标记都是顺序排序,则不难想到当前节点的父节点的标记为当前节点的标记/2;而这道题中节点的标记是“Z”字形的,那还是可以延用这种思想,然后做个反转即可。
- 记根节点所在的层为第一层,往下的层类推;
- 则每一层的标记范围是 [ pow(2,level-1) , pow(2,level)-1 ];
- 由于在 1+2+...+n-1+n中,我们可以知道 1+n = 2+(n-1)
- 因此要对节点标记做反转的公式为 label = ( pow(2,level-1) + pow(2,level)-1 ) - label/2
- 若题目给的每层都是按从小到大的顺序的标记,则label=label/2;
- 得到的新的label就是上一个label的父节点的标记;
class Solution {
public:
vector<int> pathInZigZagTree(int label) {
if(label==1)
return {1};
vector<int> path;
path.push_back(label);
//求出给定的节点在哪一层
int level=0,node=label;
while(node>0)
node/=2,level++;
while(1)
{
label/=2,--level;
if(label==1) //第一层即到达了根节点,不用再往下
break;
//思路中给的公式
int left=pow(2,level-1)-1,right=pow(2,level);
path.push_back(label=left+right-label);
}
path.push_back(1);
reverse(path.begin(),path.end());
return path;
}
};
三、1105. Filling Bookcase Shelves
这是一道难度为medium的动态规划好题,可惜我没做出来。在否定了贪心的策略后我就停滞不前了。
题目描述较多,请点链接进行查阅。
思路:
- 开一个数组dp[n],dp[i]表示放置好第i本书后目前书架的最小高度;
- 对每本书,从大体上看有两种情况:①该书放在新的一层;②该书与前面的书放在一起;
- 对于①,dp[i] = dp[i-1] + height[i],不难理解;
- 对于②,又要判断该书要和前面哪些书放在一起。我们的目标是使得书架总高度最小,所以我们用这个条件去约束我们的判断。dp[i] = min( dp[i] , dp[j]+max( height[j+1],...,height[i] ),且要满足width[j+1]+...+width[i] <= 每层书架的最大宽度。
- 上面的式子表示了每次将第j+1本书到第i本书放在同一层,第1本书到第j本书放到其他层,在满足不超过每层最大宽度的条件下取不同放置方式形成的该层的最小高度。
class Solution {
public:
int minHeightShelves(vector<vector<int>>& books, int shelf_width) {
int n=books.size();
vector<int> dp(n+1,0);
for(int i=1;i<=n;++i)
{
int width=books[i-1][0],height=books[i-1][1];
dp[i]=dp[i-1]+height; //每次先假设第I本书放置到新的一层,在比较与其他方式的效果差别
for(int j=i-1;j>0;--j)
{
width+=books[j-1][0];
height=max(height,books[j-1][1]);
if(width<=shelf_width)
dp[i]=min(dp[i],dp[j-1]+height);//各种放置方式取最小
else
break;
}
}
return dp[n];
}
};
要掌握这道题还得多揣摩揣摩。
四、1106. Parsing A Boolean Expression
这题虽然是hard类型的题,但我感觉并不难,有点名不副实。
给定一个布尔操作的字符串,要求解析这个字符串并返回解析到的值(true or false);每个操作符对于的操作数都用括号括起来且用逗号隔开。这种题立马就能想到肯定可以用栈做出来。
思路:
- 简单的模拟布尔表达式;
- 依次遍历字符串,将字符压栈,若碰到 ')' 则不压栈,而是弹出栈顶的内容(所有操作数)直到遇到一个操作符,然后用该操作符求解这一部分的值,再把值压栈。依此直到遍历完整个字符串。
- 最后的答案即是栈顶的值(栈的唯一一个元素)
class Solution {
public:
bool parseBoolExpr(string expression) {
stack<char> st;
for(char ch:expression)
{
if(ch==')')
solve(st);
else
st.push(ch);
}
return st.top()=='t'?true:false;
}
void solve(stack<char> &st)
{
int f=0,t=0; //记录操作数中有多少个false 和 true
while(!st.empty()&&st.top()!='(')
{
char ch=st.top();st.pop();
if(ch==',')
continue;
else if(ch=='f')
++f;
else if(ch=='t')
++t;
}
char res;
st.pop(); //弹出'('
if(!st.empty())
{
//针对操作符做相应的操作
if(st.top()=='&')
res=(f>0?'f':'t');
else if(st.top()=='|')
res=(t>0?'t':'f');
else //操作符为!时括号内之内一个操作数,不是f就是t
res=(f>0?'t':'f');
st.pop();
}
st.push(res);
}
};
discuss区有大神投机取巧用了Python的eval函数(执行一个字符串表达式并返回表达式的值)一行求出结果。
愿下一场我能全过。