*************
C++
TOPIC: 面试题 08.13. 堆箱子 - 力扣(LeetCode)
*************
再简单的看一眼困难的题目,

依然是比较困难的,我直接去看一下之前的困难的题目的核心方法:
不同子序列:需要考虑之前已经匹配过得,核心就是加法。
不适用于这道题目,经过昨天的思考,已经知道了这个核心就是排序,需要同时满足长宽高的严格递增或者严格递减顺序。
想到这,就觉得之前看过的300. 最长递增子序列 - 力扣(LeetCode),这个我还没有做,正好,来都来了,现在就给他做了吧,做一困难的,送一中等难度的,赚了。
简单地看一眼中等难度的题目:

根据经验,暴力美学不行,会超时,the aesthetics of violent还是过于优雅了。根据经验,这个起手就是动态规划而不是哈希表。为什么?因为我会看一眼标签:

整理一下思路,dp[i]代表至第 i 位,严格递增子序列的长度。这个就跟小学时候解方程一样,题目问什么,就设什么是 X 一样。
还是根据经验,暴力美学会超时:
对于每一个i,遍历之前的所有数字,即 j 从0 ~ i - 1,如果nums[i] > nums[j],那么dp[i] = max(dp[i], dp[j] + 1)。
数组的起手就是 s.size();并且初始化为1,为什么是1而不是0呢?因为即使是1个数字,也是满足题目要求的最长严格递增子序列。
然后需要两个循环:
外层循环 int i = 0; i < n; i++; // go through all the string
内层循环 int j = 0; j < i; j++; // go through all the elements before i
接着判断:
if (nums[i] > nums[j]) return (dp[i] = max(dp[i], dp[j] + 1);
手搓代码完成,行得通,先写试一试。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size(); // as before
vector<int> dp(n, 1); // initialise the dp
if (n == 0) return 0;
for (int i = 0; i < n; i++){
for (int j = 0; j < i; j++){
if (nums[i] > nums[j]){
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
int max_len = *max_element(dp.begin(), dp.end());
return max_len;
}
};
竟然没超时,真是天大的好消息。

既然这样的话,我排序3次应该可以。
首先,对箱子进行排序,按照宽度升序,如果宽度相同,再按深度升序,最后按高度升序。 这样可以确保宽度和深度都是非递减的,但是高度可能有波动。 然后,遍历每个箱子i,从0到i-1,检查是否存在箱子j,使得 width[j] < width[i], depth[j] < depth[i], height[j] < height[i] 如果存在,那么 dp[i] = max(dp[j] + height[i]),其中j满足上述条件 如果不存在,那么 dp[i] = height[i] 最后,答案就是dp数组中的最大值。
今天得学一个新的库,sort函数,功能就是排序。
复习一下之前的函数。unordered库,哈希表用到的,用于快速删除啥的。
*************
周四了,今天天气很好,设个大晴天,微风,比较冷,周末想去迪卡侬买两件摇粒绒,天冷了。
还有一件事,就是来了一个老外同事,那个身材真的是没的说,但是,闻着就不便宜的香水,最开始还算OK,但是后调就混合着浓郁的体臭,特别是空调一开,外套一脱,浓郁持久,闻久了容易头晕,真的是原地去世。
回到题目,
初步思路已经整理出来了:
初始化dp数组,大小为n,全部设为0。
然后,遍历每个i从0到n-1:
dp[i] = height[i]
for j from 0 to i-1:
if width[j] < width[i] and depth[j] < depth[i] and height[j] < height[i]:
dp[i] = max(dp[i], dp[j] + height[i]),
最后 return dp[n];
需要注意的是,这里有一个高级语法,也算不上多高级的语法,只不过我不会,我不会的语法统一称为高级语法,等我学会了以后,会很有成就感。
首先就是题目中给了 [width, depth, height],
那么就用:
box[i][0] 表示第 i 个盒子的宽度;
box[i][1] 表示第 i 个盒子的深度;
box[i][2] 表示第 i 个盒子的高度;
最难学的语来了,会有点困难,但是我不怕。
首先,我需要知道一些符号的意思:
!= 是一个比较运算符,用于比较两个值是否不相等。如果两个值不相同,表达式的结果为 true;如果两个值相同,结果为 false。
|| 是逻辑或(logical OR)运算符。它用于连接两个布尔表达式,如果至少有一个表达式为 true,则整个表达式的值为 true;只有当两个表达式都为 false 时,整个表达式的值才为 false。
&& 是逻辑与(logical AND)运算符。它用于连接两个布尔表达式,只有当两个表达式都为 true 时,整个表达式的值才为 true;如果至少有一个表达式为 false,则整个表达式的值为 false。
OK,这个题目的重点我已经掌握了90%了。
再一次开始尝试写代码,
class Solution {
public:
int pileBox(vector<vector<int>>& box) {
if (box.empty()) return 0;
// order by 0 1 2, which is width depth and height
sort(box.begin(), box.end(), [](const vector<int>& a, const vector<int>& b) {
if (a[0] != b[0]) return a[0] < b[0];
if (a[1] != b[1]) return a[1] < b[1];
return a[2] < b[2];
});
}
};
这段排序代码是抄的,仍然花了 很长时间才能看懂这段代码。
sort:标准库的排序函数,上一段内容已经学会。这里顺便学会了一个标准格式:
void sort(RandomAccessIterator first,
RandomAccessIterator last, Compare comp);
sort后面有三个元素,第一个是序列开始,第二个是序列结束,第三个是比较条件。
到这里都很好理解,计算机不明白,因此需要告诉计算机,从1到13进行比较。
更难一点的来了,就是这个比较运算的规则怎么让计算机知道呢?
再学一个高级语法,匿名函数。λ 这个高中经常用的到希腊字母,我第一次知道她的英文名字,lambda, b is silent. 所以,Lambda 表达式(也称为匿名函数)是 C++11 引入的一种方便的语法,允许你在需要函数的地方直接编写函数,而不需要提前定义函数。Lambda 表达式通常用于简短的操作,尤其是在需要提供函数作为参数的场合,如排序、查找等算法。一般表达式是:
[capture](parameters) -> return-type { function-body }
// [capture] 可选,定义了 lambda 表达式可以访问的外部变量。可以是值捕获(如 a 或 &a),也可以是列表形式(如 [x, &y])。
// &:通过引用捕获。
// =:通过值捕获。
// [this]:捕获当前对象的指针。
// (parameters) 可选,定义了匿名函数的表达式参数
// -> return-type 可选,定义了表达式返回类型
// { function-body } 现场编写的函数表达式
现在可以非常详细的解释一下抄到的代码的意思了
sort(box.begin(), box.end(), [](const vector<int>& a, const vector<int>& b) {
// sort means using the function
// box.begin() and box.end() means where is start and where is end
// [] tell lanbda can visit the outside data
// const means the data comes second cannot be changed
// capture by reference
box.begin() 定义开始的位置;
box.end() 定义结束的位置;
[] 固定格式,
可选。定义了 lambda 表达式可以访问的外部变量。可以是值捕获(如 a 或 &a),也可以是列表形式(如 [x, &y])。
&:通过引用捕获。=:通过值捕获。[this]:捕获当前对象的指针。
const,我觉得是constant的缩写,常量,恒定不变的,这个意味着后面引用的值不能被改变。
const vector<int>& a, const vector<int>& b 是引用 a b 两个值。
在看别人进行比较的函数的时候,我有个点一直不明白,先看代码:
sort(box.begin(), box.end(), [](const vector<int>& a, const vector<int>& b) {
if (a[0] != b[0]) return a[0] < b[0];
if (a[1] != b[1]) return a[1] < b[1];
return a[2] < b[2];
});
这里为什么 a[0] != b[0] 就直接输出 a[0] < b[0]呢,这里哪里做了比较呢?根本就没有比较的过程,不相等就可以直接进行比较吗?
我行明白了,这个是函数过程,不是函数结果,这个代码实现的功能就是,
如果宽度不一样,宽度小的那个排在前面。
整体的函数实现的功能就是:
- 比较宽度,如果宽度不同,直接按宽度升序排列。
- 如果宽度相同,比较深度,按深度升序排列。
- 如果宽度和深度都相同,比较高度,按高度升序排列。
最重要的比较函数写明白了,就可以让箱子排列了。
首先就是知道一共有多少个箱子 box.size();
其次就是初始化一个数组
class Solution {
public:
int pileBox(vector<vector<int>>& box) {
if (box.empty()) return 0;
// order by 0 1 2, which is width depth and height
sort(box.begin(), box.end(), [](const vector<int>& a, const vector<int>& b) {
// sort means using the function
// box.begin() and box.end() means where is start and where is end
// [] tell lanbda can visit the outside data
// const means the data comes second cannot be changed
// capture by reference
if (a[0] != b[0]) return a[0] < b[0];
if (a[1] != b[1]) return a[1] < b[1];
return a[2] < b[2];
});
int n = box.size(); // get the numbers of the boxes
vector<int> dp(n, 0); // initialise the dp and assign 0
}
};
对箱子进行遍历循环,并给高度一个初始值,这个也很简单
class Solution {
public:
int pileBox(vector<vector<int>>& box) {
if (box.empty()) return 0;
// order by 0 1 2, which is width depth and height
sort(box.begin(), box.end(), [](const vector<int>& a, const vector<int>& b) {
// sort means using the function
// box.begin() and box.end() means where is start and where is end
// [] tell lanbda can visit the outside data
// const means the data comes second cannot be changed
// capture by reference
if (a[0] != b[0]) return a[0] < b[0];
if (a[1] != b[1]) return a[1] < b[1];
return a[2] < b[2];
});
int n = box.size(); // get the numbers of the boxes
vector<int> dp(n, 0); // initialise the dp and assign 0
for (int i = 0; i < n; ++i) {
dp[i] = box[i][2]; // initial height
}
};
内层循环,对排在 i 前面的箱子 j 和 i 进行比较,
class Solution {
public:
int pileBox(vector<vector<int>>& box) {
if (box.empty()) return 0;
// order by 0 1 2, which is width depth and height
sort(box.begin(), box.end(), [](const vector<int>& a, const vector<int>& b) {
// sort means using the function
// box.begin() and box.end() means where is start and where is end
// [] tell lanbda can visit the outside data
// const means the data comes second cannot be changed
// capture by reference
if (a[0] != b[0]) return a[0] < b[0];
if (a[1] != b[1]) return a[1] < b[1];
return a[2] < b[2];
});
int n = box.size(); // get the numbers of the boxes
vector<int> dp(n, 0); // initialise the dp and assign 0
for (int i = 0; i < n; ++i) {
dp[i] = box[i][2]; // initial height
for (int j = 0; j < i; ++j) {
}
};
需要同事满足3个条件,box[j][0] < box[i][0] && box[j][1] < box[i][1] && box[j][2] < box[i][2];
那么最大的高度就可以更新为dp[i] = max(dp[i], dp[j] + box[i][2])。
class Solution {
public:
int pileBox(vector<vector<int>>& box) {
if (box.empty()) return 0;
// order by 0 1 2, which is width depth and height
sort(box.begin(), box.end(), [](const vector<int>& a, const vector<int>& b) {
// sort means using the function
// box.begin() and box.end() means where is start and where is end
// [] tell lanbda can visit the outside data
// const means the data comes second cannot be changed
// capture by reference
if (a[0] != b[0]) return a[0] < b[0];
if (a[1] != b[1]) return a[1] < b[1];
return a[2] < b[2];
});
int n = box.size(); // get the numbers of the boxes
vector<int> dp(n, 0); // initialise the dp and assign 0
for (int i = 0; i < n; ++i) {
dp[i] = box[i][2]; // initial height
for (int j = 0; j < i; ++j) {
if (box[j][0] < box[i][0] && box[j][1] < box[i][1] && box[j][2] < box[i][2]) {
dp[i] = max(dp[i], dp[j] + box[i][2]);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};
注意注意,代码是从上往下运行的,因此 for 函数那段,就是对已经排序过的箱子进行筛选。
举个例子:
box 1 = [2, 2, 3],
box 2 = [1, 1, 4],
box 3 = [3, 3, 2]
排序后:
box 2 = [1,1,4],
box 1 = [2,2,3],
box 3 = [3,3,2]
dp=[0,0,0]
i=0:
dp[0]=4
i=1:
dp[1]=3
j=0:
1 < 2, 1 < 2, 4 < 3? 不满足
dp[1]=3
i=2:
dp[2]=2
j=0:
1 < 3, 1 < 3, 4 < 2? 不满足
j=1:
2 < 3, 2 < 3, 3 < 2? 不满足
dp[2]=2
所以,dp=[4,3,2], 返回4。

不出意外的,过两天又会忘记这个代码。忘了那就再学一遍。
have a good day.

1331

被折叠的 条评论
为什么被折叠?



