给你两个长度相同的整数数组 target
和 arr
。
每一步中,你可以选择 arr
的任意 非空子数组 并将它翻转。你可以执行此过程任意次。
如果你能让 arr
变得与 target
相同,返回 True;否则,返回 False 。
示例 1
输入:target = [1,2,3,4], arr = [2,4,1,3]
输出:true
解释:你可以按照如下步骤使 arr 变成 target:
1- 翻转子数组 [2,4,1] ,arr 变成 [1,4,2,3]
2- 翻转子数组 [4,2] ,arr 变成 [1,2,4,3]
3- 翻转子数组 [4,3] ,arr 变成 [1,2,3,4]
上述方法并不是唯一的,还存在多种将 arr 变成 target 的方法。
示例 2
输入:target = [7], arr = [7]
输出:true
解释:arr 不需要做任何翻转已经与 target 相等。
示例 3
输入:target = [1,12], arr = [12,1]
输出:true
示例 4
输入:target = [3,7,9], arr = [3,7,11]
输出:false
解释:arr 没有数字 9 ,所以无论如何也无法变成 target 。
示例 5
输入:target = [1,1,1,1,1], arr = [1,1,1,1,1]
输出:true
提示
- target.length == arr.length
拿到第一题其实我有点懵的 因为假如用模拟翻转的话这题将会变得相当复杂
然后想了下这里是有这样一个结论的:
然后我猜出来之后当然要简单证明下 不然就会吃一个WA不值得
总的复杂度是遍历两个的复杂度 O(n)
其实贪快的话直接构造函数塞进multiset然后判断下是否相等就好了
class Solution {
public:
bool canBeEqual(vector<int>& target, vector<int>& arr) {
int n=target.size();
map<int,int> m1,m2; //我这里没用multiset 用的计数
for(int i=0;i<n;i++)
{
m1[target[i]]++;
m2[arr[i]]++;
}
for(auto i:m1)
if(m2[i.first]!=i.second)return false;
return true;
}
};
给你一个二进制字符串 s
和一个整数 k
。
如果所有长度为 k
的二进制字符串都是 s
的子串,请返回 True ,否则请返回 False 。
示例 1
输入:s = “00110110”, k = 2
输出:true
解释:长度为 2 的二进制串包括 “00”,“01”,“10” 和 “11”。它们分别是 s 中下标为 0,1,3,2 开始的长度为 2 的子串。
示例 2
输入:s = “00110”, k = 2
输出:true
示例 3
输入:s = “0110”, k = 1
输出:true
解释:长度为 1 的二进制串包括 “0” 和 “1”,显然它们都是 s 的子串。
示例 4
输入:s = “0110”, k = 2
输出:false
解释:长度为 2 的二进制串 “00” 没有出现在 s 中。
示例 5
输入:s = “0000000001011100”, k = 4
输出:false
提示
- 1 <= s.length <= 5 * 10^5
这里我们先分析下题目
题目需要我们判断子串中是否有全部k以内的数字 那么你肯定就得把子串都弄出来才能判断
因此 上来先把s中全部长度为k的子串存起来 用substr就好了 一次复杂度是O(k)的
那么用什么存起来呢 这里我们想要知道他是否存在 那么直接就用set保存就行了
然后就是判断部分了 我们可以选择从0开始的全部字符串形式的数字都弄出来 然后再去看一下它在不在里面 如果有不在的话就直接返回false就行了
我再考虑了一下(赛后) 其实完全没有必要把字符串造出来 因为set的大小最大就是2的k次方 而且如果想要全部数字匹配的话 那么set只能是最大那个大小 所以直接判断下set的大小是不是为2的k次方就行了
class Solution {
public:
bool hasAllCodes(string s, int k) {
if(s.size()<k)return false; //题目没说k必须比s长度小
unordered_set<string> Set;
for(int i=0;i<s.size()-k+1;i++)Set.insert(s.substr(i,k));
return Set.size()==(1<<k);
}
};
你总共需要上 n 门课,课程编号依次为 0 到 n-1 。
有的课会有直接的先修课程,比如如果想上课程 0 ,你必须先上课程 1 ,那么会以 [1,0] 数对的形式给出先修课程数对。
给你课程总数 n 和一个直接先修课程数对列表 prerequisite
和一个查询对列表 `queries 。
对于每个查询对 queries[i]
,请判断 queries[i][0]
是否是 queries[i][1]
的先修课程。
请返回一个布尔值列表,列表中每个元素依次分别对应 queries
每个查询对的判断结果。
注意:如果课程 a 是课程 b 的先修课程且课程 b 是课程 c 的先修课程,那么课程 a 也是课程 c 的先修课程。
示例 1
输入:n = 2, prerequisites = [[1,0]], queries = [[0,1],[1,0]]
输出:[false,true]
解释:课程 0 不是课程 1 的先修课程,但课程 1 是课程 0 的先修课程。
示例 2
输入:n = 2, prerequisites = [], queries = [[1,0],[0,1]]
输出:[false,false]
解释:没有先修课程对,所以每门课程之间是独立的。
示例 3
输入:n = 3, prerequisites = [[1,2],[1,0],[2,0]], queries = [[1,0],[1,2]]
输出:[true,true]
示例 4
输入:n = 3, prerequisites = [[1,0],[2,0]], queries = [[0,1],[2,0]]
输出:[false,true]
示例 5
输入:n = 5, prerequisites = [[0,1],[1,2],[2,3],[3,4]], queries = [[0,4],[4,0],[1,3],[3,0]]
输出:[true,false,true,false]
提示
- 2 <=
n
<= 100
prerequisite.length
<= (n * (n - 1) / 2)prerequisite[i][0]
, prerequisite[i][1]
< nprerequisite[i][0]
!= prerequisite[i][1]
queries.length
<= 10^4queries[i][0]
!= queries[i][1]
我一开始看到题目想的是拓扑排序 就是判断一下询问前者是不是在拓扑序上的前者 但是后来发现这题图不一定是连通的 也就是会分割成多个图的 那么这种情况就需要对每个图分别进行拓扑序 然后还要判断是不是在同一个图中 这样就有点麻烦
我再看了下复杂度 最多有100个节点 也就是说最多有1e4个两两关系
那么假如我对这1e4个两两关系进行一次连通判断 那么跑完整个图也只需要1e6而已 这个复杂度完全可以接受
所以总的复杂度是O(n^3) 与询问的size无关 询问最多就是边的数量n^2
这题有点特殊 就特殊在询问的次数受边数限制 可以对于每条边都去跑一次图 不然的话很显然是要预处理关系的
最短路预处理
赛后想了下 直接用floyd跑下多源最短路就行了
复杂度还是O(n^3)
class Solution {
public:
vector<unordered_set<int>> G; //这里如果直接用二维数组存图可能在bfs时候复杂度上升
vector<bool> checkIfPrerequisite(int n, vector<vector<int>>& p, vector<vector<int>>& Q) {
G.resize(n);
for(auto i:p) //邻接矩阵存图
G[i[0]].insert(i[1]);
vector<bool> ans;
for(auto i:Q)
if(bfs(i[0],i[1]))ans.push_back(true);
else ans.push_back(false);
return ans;
}
bool bfs(int a,int b) //判断是否可达
{
queue<int> q;
q.push(a);
int vis[105]={0};
vis[a]=true;
while(q.size())
{
int x=q.front();
q.pop();
for(auto i:G[x])
if(i==b)return true;
else if(!vis[i]){
vis[i]=true;
q.push(i);
}
}
return false;
}
};`
class Solution {
public:
bool d[105][105];
vector<bool> ans;
vector<bool> checkIfPrerequisite(int n, vector<vector<int>>& prerequisites, vector<vector<int>>& queries) {
int i,j,k;
memset(d,0,sizeof(d));
for(i=0;i<n;i++)d[i][i]=1;
for(auto e:prerequisites)d[e[0]][e[1]]=1;
for(k=0;k<n;k++)for(i=0;i<n;i++)for(j=0;j<n;j++)d[i][j]=d[i][j]||d[i][k]&&d[k][j];
ans.clear();
for(auto q:queries)ans.push_back(d[q[0]][q[1]]);
return ans;
}
};
给你一个 rows x cols 的矩阵 grid 来表示一块樱桃地。 grid 中每个格子的数字表示你能获得的樱桃数目。
你有两个机器人帮你收集樱桃,机器人 1 从左上角格子 (0,0) 出发,机器人 2 从右上角格子 (0, cols-1) 出发。
请你按照如下规则,返回两个机器人能收集的最多樱桃数目:
示例 1
输入:grid = [[3,1,1],[2,5,1],[1,5,5],[2,1,1]]
输出:24
解释:机器人 1 和机器人 2 的路径在上图中分别用绿色和蓝色表示。
机器人 1 摘的樱桃数目为 (3 + 2 + 5 + 2) = 12 。
机器人 2 摘的樱桃数目为 (1 + 5 + 5 + 1) = 12 。
樱桃总数为: 12 + 12 = 24 。
示例 2
输入:grid = [[1,0,0,0,0,0,1],[2,0,0,0,0,3,0],[2,0,9,0,0,0,0],[0,3,0,5,4,0,0],[1,0,2,3,0,0,6]]
输出:28
解释:机器人 1 和机器人 2 的路径在上图中分别用绿色和蓝色表示。
机器人 1 摘的樱桃数目为 (1 + 9 + 5 + 2) = 17 。
机器人 2 摘的樱桃数目为 (1 + 3 + 4 + 3) = 11 。
樱桃总数为: 17 + 11 = 28 。
示例 3
输入:grid = [[1,0,0,3],[0,0,0,3],[0,0,3,3],[9,0,3,3]]
输出:22
示例 4
输入:grid = [[1,1],[1,1]]
输出:4
提示
- rows ==
grid.length
grid[i].length
grid[i][j]
<= 100如果只有一个机器人的话 那么这个问题就是经典的三角数字dp问题
我们来看下如果只有一个是怎样的
定义状态dp[i][j]
为选到第i行第j列的时候 后面总共的最大值
那么我们站在第i行第j列的时候 我们就只需要考虑三个的大小问题而已:
dp[i+1][j-1]
dp[i+1][j]
dp[i+1][j+1]
那么直到最后一行就不用考虑了
那么一个机器人很明显 那么两个呢
我的第一个想法是能否先跑一次一个机器人 然后把途中的樱桃数量都变为0 然后再去跑第二个 但是后来发现这个是不可行的 因为两次都是按照最优的去选择 并不会出现相遇时候去选择次优的
(主要是因为两个机器人能选取的范围不同 假如第一个机器人实际上要选的是较左的次优 那么右边机器人第二次跑显然就选不到了)
既然两个机器人的状态互相有影响 那么我们直接多定义一个机器人的状态就好了
定义dp[i][j1][j2]
为在第i行的时候两个机器人分别在j1和j2列
那么移动的时候就有3 * 3种可能了 在9种可能里面选最大的就行了
然后呢 用记忆化搜索将会使移动更加直观
总的复杂度是状态的填充O(n^3)
int dy[]={-1,0,1}; //移动的方向
class Solution {
public:
vector<vector<int>> G;
int mem[75][75][75]; //记忆数组
int n,m;
int cherryPickup(vector<vector<int>>& grid) {
G=grid;
n=G.size();
m=G[0].size();
memset(mem,-1,sizeof(mem));
return ms(0,0,m-1); //搜索初始状态就是答案
}
int ms(int i,int j1,int j2)
{
if(j1<0||j2<0||j1>=m||j2>=m)return 0;
if(i==n-1){ //最后一行
if(j1!=j2)return G[i][j1]+G[i][j2];
return G[i][j1];
}
int &now=mem[i][j1][j2]; //简化书写
if(now!=-1)return now;
if(j1!=j2)now=G[i][j1]+G[i][j2];
else now=G[i][j1];
int Max=0;
for(int ii=0;ii<3;ii++) //多种移动选最优的
for(int jj=0;jj<3;jj++)
Max=max(Max,ms(i+1,j1+dy[ii],j2+dy[jj]));
now+=Max;
return now;
}
};