1103. Distribute Candies to People
给定两个整数,分别表示糖果数和人数,按顺序给第i个人分配i+1个糖果,若第二个循环,则给第i个人i + 1 + N个糖果
返回最后每个人拥有的糖果数
直接初始化整个数组,然后遍历一遍即可
class Solution {
public:
vector<int> distributeCandies(int candies, int num_people) {
vector<int> res(num_people, 0);
int pos = 0;
while(candies > 0)
{
if(pos + 1 >= candies)
{
res[pos % num_people] += candies;
candies = 0;
}
else
{
res[pos % num_people] += (pos + 1);
candies = candies - pos - 1;
}
pos++;
}
return res;
}
};
1104. Path In Zigzag Labelled Binary Tree
Zigzag的遍历方法如图所示,深度为奇数的从左往右,深度为偶数的从右往左
给定一个节点值,返回从根节点到该节点的路径
其实如果是正常的二叉树,某一个节点a与其父节点b的关系为 b = a / 2(取整)
因此这里可以先找出来该节点对应于正常的树的值,考虑到对于每一层(设深度为h),最小的元素为minn = 2h-1 , 最大的元素为maxn = 2h-1,因此先找到其在正常二叉树的对应值:n = (minn + maxn - val),然后保存n / 2即可
最后对返回值reverse翻转
class Solution {
public:
vector<int> pathInZigZagTree(int label) {
vector<int> res;
while(label)
{
res.emplace_back(label);
int layer = log2(label) + 1;
int relative = pow(2, layer) - 1 + pow(2, layer - 1) - label;
label = relative / 2;
}
reverse(res.begin(), res.end());
return res;
}
};
1105. Filling Bookcase Shelves
给定一个二维数组,每个元素表示一本书的宽度和高度,shelf_width表示一个书架的宽度
将书按序放置,求最小堆叠的高度
首先注意这里是按序放置,也就是不能先放第一本书再放第三本,后放第二本
其次,这是一道动态规划的问题
对于第i + 1本书,有两种放置方法:
- 直接放到下面新的一层,则dp[i + 1] = dp[i] + books[i + 1][1]
- 将其尽可能多地与前面的书合并,则需要从i + 1反过来遍历,找到最多能合并的书的个数,及其对应的高度。这里“最多的书的数量”取决于这些书的宽度之和,需要小于等于shelf_width
有了这两点,就可以得到如下代码:
#define fo(i, a, b) for(int i = a; i < b; ++i)
class Solution {
public:
int minHeightShelves(vector<vector<int>>& books, int shelf_width) {
vector<int> dp(books.size() + 1, 0);
fo(i, 0, books.size())
{
dp[i + 1] = dp[i] + books[i][1];
int curh = 0, curw = 0;
for (int j = i; j >= 0; --j)
{
curw += books[j][0];
if (curw > shelf_width) break;
else
{
curh = max(curh, books[j][1]);
dp[i + 1] = min(dp[i + 1], dp[j] + curh);
}
}
}
return dp[books.size()];
}
};
1106. Parsing A Boolean Expression
给定一个字符串,返回运算结果
运算规则:
- “t” 、 “f” 分别表示true 和 false
- !(exp) 表示exp的相反值
- &(exp1, exp2, exp3) 表示exp1、exp2、exp3等 与运算 的结果
- |(exp1, exp2, exp3) 表示exp1、exp2、exp3等做 或运算 的结果
一看到括号就想用栈,但这道题似乎不适用,然后就是递归,举个例子:
!(&(&(f),&(!(t),&(f),|(f)),&(!(&(f)),&(t),|(f,f,t))))
开头是’!’,则相当于返回后面整个大括号里&(&(f),&(!(t),&(f),|(f)),&(!(&(f)),&(t),|(f,f,t)))
的相反值
而对’&'开头的运算符,可以用一个函数将其括号内的表达式进行分解,得到
{[&(f)], [&(!(t),&(f),|(f))], [&(!(&(f)),&(t),|(f,f,t))]}
这三个子表达式
至于如何分解,可以通过括号得到所对应的层数,后面看代码即可
那么由于是与运算,即对这三个子表达式对应的结果做与运算,而子表达式的运算结果,则可以通过递归调用获得
于是代码为:
#define fo(i, a, b) for(int i = a; i < b; ++i)
class Solution {
public:
vector<string> splitExpression(string exp)
{
vector<string> vs;
// 括号层数
int layer = 0;
string s = "";
fo(i, 0, exp.length())
{
if (exp[i] == ',' && layer == 0)
{
vs.emplace_back(s);
s = "";
continue;
}
s += exp[i];
if (exp[i] == '(') layer++;
if (exp[i] == ')') layer--;
}
if (s.length()) vs.emplace_back(s);
return vs;
}
bool parseBoolExpr(string expression) {
int len = expression.length();
if (expression.length() == 1) return expression[0] == 't';
// 若开头为!,返回其值域的作用域,作用域为expression.substr(2, len - 3)
if (expression[0] == '!') return !parseBoolExpr(expression.substr(2, len - 3));
vector<string> exp = splitExpression(expression.substr(2, len - 3));
if (expression[0] == '|')
{
bool res = false;
for (string s : exp)
{
res |= parseBoolExpr(s);
}
return res;
}
else
{
bool res = true;
for (string s : exp)
{
res &= parseBoolExpr(s);
}
return res;
}
}
};