1、用栈操作构建数组(3分)
题目描述
给你一个目标数组 target
和一个整数n
。每次迭代,需要从 list = {1,2,3..., n}
中依序读取一个数字。
请使用下述操作来构建目标数组target
:
- Push:从 list 中读取一个新元素, 并将其推入数组中。
- Pop:删除数组中的最后一个元素。
- 如果目标数组构建完成,就停止读取更多元素。
题目数据保证目标数组严格递增,并且只包含1
到 n
之间的数字。
请返回构建目标数组所用的操作序列。
题目数据保证答案是唯一的。
示例 1:
输入:target = [1,3], n = 3
输出:["Push","Push","Pop","Push"]
解释:
读取 1 并自动推入数组 -> [1]
读取 2 并自动推入数组,然后删除它 -> [1]
读取 3 并自动推入数组 -> [1,3]
示例 2:
输入:target = [1,2,3], n = 3
输出:["Push","Push","Push"]
示例 3:
输入:target = [1,2], n = 4
输出:["Push","Push"]
解释:只需要读取前 2 个数字就可以停止。
示例 4:
输入:target = [2,3,4], n = 4
输出:["Push","Pop","Push","Push","Push"]
提示:
1 <= target.length <= 100
1 <= target[i] <= 100
1 <= n <= 100
target 是严格递增的
解题思路
- 题目中所给的
n
值是没有用的,记住target
数组的最后一个值即可。 - 分两种情况,(1)
target[i]
等于list[i]
所对应的值,此时执行Push
操作即可;(2)target[i]
所对应的值大于相应的list[i]
的值,说明有出栈的数字,此时依次执行Push,Pop
直到target[i]
和list[i]
的值相对应即可。
代码实现
class Solution {
public:
vector<string> buildArray(vector<int>& target, int n) {
vector<string> svec;
int count = 1;
for(int i = 0; i < target.size(); i++)
{
while(target[i] > count)
{
svec.push_back("Push");
svec.push_back("Pop");
count++;
}
if(target[i] == count)
{
svec.push_back("Push");
count++;
}
}
return svec;
}
};
运行截图
2、形成两个异或相等数组的三元组数目(4分)
题目描述
给你一个整数数组 arr
。
现需要从数组中取三个下标i
、j
和 k
,其中(0 <= i < j <= k < arr.length)
。
a
和 b
定义如下:
a = arr[i] ^ arr[i + 1] ^ ... ^ arr[j - 1]
b = arr[j] ^ arr[j + 1] ^ ... ^ arr[k]
注意:^
表示 按位异或 操作。
请返回能够令a == b
成立的三元组 (i, j , k)
的数目。
示例 1:
输入:arr = [2,3,1,6,7]
输出:4
解释:满足题意的三元组分别是 (0,1,2), (0,2,2), (2,3,4) 以及 (2,4,4)
示例 2:
输入:arr = [1,1,1,1,1]
输出:10
示例 3:
输入:arr = [2,3]
输出:0
示例 4:
输入:arr = [1,3,5,7,9]
输出:3
示例 5:
输入:arr = [7,11,12,9,5,2,7,17,22]
输出:8
提示:
1 <= arr.length <= 300
1 <= arr[i] <= 10^8
解题思路
- 直接使用暴力求解,三层
for
循环取遍i
,j
和k
所在位置的所有情况。 - C++中使用运算符
^
可以直接实现两个十进制数的按位异或运算。
代码实现
class Solution {
public:
int countTriplets(vector<int>& arr) {
if(arr.size() < 2)
return 0;
if(arr.size() == 2)
return arr[0] == arr[1] ? 1 : 0;
int count = 0;
for(int i = 0; i < arr.size(); i++)
{
int num1 = arr[i];
for(int j = i + 1; j < arr.size(); j++)
{
int num2 = 0;
for(int k = j; k < arr.size(); k++)
{
num2 ^= arr[k];
if(num1 == num2)
count++;
}
num1 ^= arr[j];
}
}
return count;
}
};
运行截图
3、收集树上所有苹果的最少时间(5分)
题目描述
给你一棵有n
个节点的无向树,节点编号为0
到n-1
,它们中有一些节点有苹果。通过树上的一条边,需要花费1
秒钟。你从节点0
出发,请你返回最少需要多少秒,可以收集到所有苹果,并回到节点0
。
无向树的边由 edges
给出,其中
e
d
g
e
s
[
i
]
=
[
f
r
o
m
i
,
t
o
i
]
edges[i] = [from_i, to_i]
edges[i]=[fromi,toi],表示有一条边连接
f
r
o
m
i
from_i
fromi和
t
o
i
to_i
toi。除此以外,还有一个布尔数组 hasApple
,其中 hasApple[i] = true
代表节点i
有一个苹果,否则,节点i
没有苹果。
示例 1:
输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]],
hasApple = [false,false,true,false,true,true,false]
输出:8
解释:上图展示了给定的树,其中红色节点表示有苹果。
一个能收集到所有苹果的最优方案由绿色箭头表示。
示例 2:
输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]],
hasApple = [false,false,true,false,false,true,false]
输出:6
解释:上图展示了给定的树,其中红色节点表示有苹果。
一个能收集到所有苹果的最优方案由绿色箭头表示。
示例 3:
输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]],
hasApple = [false,false,false,false,false,false,false]
输出:0
提示:
1 <= n <= 10^5
edges.length == n-1
edges[i].length == 2
0 <= fromi, toi <= n-1
fromi < toi
hasApple.length == n
解题思路
- 要收集到每个苹果,最基本的方法就是每个有苹果的结点遍历一次,如果某些节点本身没有苹果并且其子树没有苹果的结点,无需遍历。
- 统计到所有有苹果的结点,依次遍历,就是其最佳找苹果的路径。
- 本质方法就是使用图的深度优先遍历算法,但是在解答的过程中遇到了问题,对于这样的例子:
[0,2],[0,3],[1,2]、[false,true,false,false]
显然是一个“有向”图,即结点0和结点1均指向结点2,如果还是用上述图的深度优先遍历算法并将结点本身或者以该结点为根的子树没有苹果的结点丢弃的方法,就会出现问题。对于该例,从结点0开始遍历,会发现结点0,结点2,结点3均符合丢弃的情况,但本例的真正含义是从0到2再到1再返回,是4步,显然不合题意,但是网上的很多“标准答案”都是这样写的。 - 我的思路是定义一个路径反转函数,如果之前的路径里面的弧头是其余路径的弧尾,就将其转置。但这样做又会对100000个例子的情况就会超时,所以这里就有了一个技巧,在路径较少的时候调用了这个函数。
代码实现
class Solution {
public:
void reverseedge(vector<vector<int>>& edges)
{// 路径反转函数 每一次都调用的话 会超出时间限制
if(edges.size() == 1)
return;
for(int i = 0; i < edges.size(); i++)
for(int j = i + 1; j < edges.size(); j++)
if(edges[i][1] == edges[j][1])
{
int temp = 0;
temp = edges[j][0];
edges[j][0] = edges[j][1];
edges[j][1] = temp;
}
}
bool DFS_FindAppleNode(int inode, vector<bool>& hasApple)
{ // 属于无向图的深度优先遍历
bool nodehasApple = hasApple[inode];
for(auto& i : iumap[inode])
nodehasApple = DFS_FindAppleNode(i, hasApple) or nodehasApple;
if(nodehasApple == false)
iumap.erase(inode);
return nodehasApple;
}
int minTime(int n, vector<vector<int>>& edges, vector<bool>& hasApple) {
if(edges.size() < 100) // 使用了一个技巧 在数量比较小的时候调用
reverseedge(edges); // 结果就AC了
for(auto& edge : edges)
iumap[edge[0]].push_back(edge[1]);
DFS_FindAppleNode(0, hasApple);
return iumap.size() == 0 ? 0 : 2 * (int)(iumap.size() - 1);
}
private:
unordered_map<int, vector<int>> iumap;
};
所以该代码需要进一步改进!!!
4、切披萨的方案数(7分)
问题描述
给你一个
r
o
w
s
×
c
o
l
s
rows\times{cols}
rows×cols 大小的矩形披萨和一个整数k
,矩形包含两种字符:'A'
(表示苹果)和'.'
(表示空白格子)。你需要切披萨k-1
次,得到 k
块披萨并送给别人。
切披萨的每一刀,先要选择是向垂直还是水平方向切,再在矩形的边界上选一个切的位置,将披萨一分为二。如果垂直地切披萨,那么需要把左边的部分送给一个人,如果水平地切,那么需要把上面的部分送给一个人。在切完最后一刀后,需要把剩下来的一块送给最后一个人。
请你返回确保每一块披萨包含 至少 一个苹果的切披萨方案数。由于答案可能是个很大的数字,请你返回它对10^9 + 7
取余的结果。
示例 1:
输入:pizza = ["A..","AAA","..."], k = 3
输出:3
解释:上图展示了三种切披萨的方案。注意每一块披萨都至少包含一个苹果。
示例 2:
输入:pizza = ["A..","AA.","..."], k = 3
输出:1
示例 3:
输入:pizza = ["A..","A..","..."], k = 1
输出:1
提示:
1 <= rows, cols <= 50
rows == pizza.length
cols == pizza[i].length
1 <= k <= 10
pizza 只包含字符 'A' 和 '.'
解题思路
代码实现
#define ll long long int
class Solution {
public:
const ll mod=1e9+7;
int ways(vector<string>& pizza, int k) {
int row=pizza.size(),col=pizza[0].length();
//计算num
vector<vector<int>> num(row,vector<int>(col,0));
if(pizza[0][0]=='A') num[0][0]=1;
for(int i=1;i<row;i++) num[i][0]=num[i-1][0]+(pizza[i][0]=='A');
for(int i=1;i<col;i++) num[0][i]=num[0][i-1]+(pizza[0][i]=='A');
for(int i=1;i<row;i++) for(int j=1;j<col;j++)
num[i][j]=num[i-1][j]+num[i][j-1]-num[i-1][j-1]+(pizza[i][j]=='A');
//初始化dp
vector<vector<vector<ll>>> dp(row,vector<vector<ll>>(col,vector<ll>(k+1,0)));
dp[0][0][1]=1;
//从k=2开始填充
for(int x=2;x<=k;x++){
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
//dp为0代表不存在这种情况
if(dp[i][j][x-1]==0)
continue;
//穷举水平切
for(int z=i+1;z<row;z++){
if(hasA(num,i,j,z-1,col-1) && hasA(num,z,j,row-1,col-1)){
dp[z][j][x]+=dp[i][j][x-1];
dp[z][j][x]%=mod;
}
}
//穷举垂直切
for(int z=j+1;z<col;z++){
if(hasA(num,i,j,row-1,z-1) && hasA(num,i,z,row-1,col-1)){
dp[i][z][x]+=dp[i][j][x-1];
dp[i][z][x]%=mod;
}
}
}
}
}
//计算答案
ll ans=0;
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
ans+=dp[i][j][k];
}
ans%=mod;
}
return ans;
}
//计算存在A吗
bool hasA(vector<vector<int>>& num,int sr,int sc,int er,int ec){
int num1=0,num2=0,num3=0,res;
if(sr!=0 && sc!=0) num1=num[sr-1][sc-1];
if(sr!=0) num2=num[sr-1][ec];
if(sc!=0) num3=num[er][sc-1];
return num[er][ec]-num2-num3+num1>0;
}
};