Leetcode周赛专题
204场周赛
5500. 乘积为正数的最长子数组长度
解题思路:
我们使用两个数组来进行动态规划,分别为p_dp[i]:以 i 结尾乘积为正数得最长子数组长度 n_dp[i]:以 i 结尾乘积为负数得最长子数组长度。当nums[i]为不同情况时,每个数组得不同操作如下:
- nums[i] > 0时,p_dp[i] = p_dp[i - 1] + 1即可。n_dp[i] 要根据n_dp[i - 1] 是否存在负数得最长子数组,若存在则乘上一个正数还是负数所以n_dp[i] = n_dp[i - 1] + 1,若不存在则n_dp[i] = 0
- nums[i] < 0时,p_dp[i]要根据n_dp[i - 1],因为若以i - 1结尾乘积为负数得最长子数组长度乘上一个负数,则肯定为以 i 结尾乘积为正数得最长子数组长度。同样得道理,n_dp[i] 根据 p_dp[i - 1]乘上一个负数得到最长子数组长度。
- nums[i] == 0时,p_dp和n_dp都不会选择得,所以全部重置为0即可
代码:
class Solution {
public:int getMaxLen(vector<int>& nums) {int sz = nums.size();vector<int> p_dp(sz);vector<int> n_dp(sz);p_dp[0] = nums[0] > 0 ? 1 : 0;n_dp[0] = nums[0] < 0 ? 1 : 0;int res = p_dp[0];for(int i = 1; i < sz; i++) {if(nums[i] > 0) {p_dp[i] = p_dp[i - 1] + 1;n_dp[i] = n_dp[i - 1] > 0 ? n_dp[i - 1] + 1 : 0;} else if(nums[i] < 0) {p_dp[i] = n_dp[i - 1] > 0 ? n_dp[i - 1] + 1 : 0;n_dp[i] = p_dp[i - 1] + 1;} else {p_dp[i] = 0;n_dp[i] = 0;}res = max(res , p_dp[i]);}return res;}
};
总结:
- 这里得dp数组每个都是局部求解,因为在遇到0时,我们全部重置了,重置后得结果可能不是最优解,所以我们不能直接返回p_dp[sz - 1],要使用res单独存储起来,每次都更新。
- 这题得难点不在于动态规划得思想,在于两个不同状态得切换求值,当nums[i] > 0 或者nums[i] < 0时,如果通过另一个状态来求得该状态得值。我们只是把两种状态使用数组表示而已
1568. 使陆地分离的最少天数
解题思路:
设置check函数判断是否只存在一个岛屿,我们只要检查是否删除一个陆地后都都会存在一个岛屿,那么我们只要找到一个相邻有4条边得陆地,删除以它和它得对角一个陆地,即可分离出两个岛屿了。
代码:
class Solution {
public:int dx[4] = {1 , 0 , -1 , 0};int dy[4] = {0 , 1 , 0 , -1};bool isInside(const vector<vector<int>>& grid , int x , int y) {return x >= 0 && x < grid.size() && y >= 0 && y < grid[0].size();}bool check(const vector<vector<int>>& grid) {int x , y , count = 0;for(int i = 0; i < grid.size(); i++) {for(int j = 0; j < grid[i].size(); j++) {if(grid[i][j] == 0) continue;count++;x = i;y = j;}}queue<pair<int , int>> q;bool mark[30][30] = {0};q.push(make_pair(x , y));mark[x][y] = true;count--;while(!q.empty()) {auto f = q.front();q.pop();for(int i = 0; i < 4; i++) {int nx = f.first + dx[i] , ny = f.second + dy[i];if(isInside(grid , nx , ny) && grid[nx][ny] == 1) {if(mark[nx][ny]) continue;mark[nx][ny] = true;q.push(make_pair(nx , ny));count--;}}}return count != 0;}int minDays(vector<vector<int>>& grid) {if(check(grid)) return 0;for(int i = 0; i < grid.size(); i++) {for(int j = 0; j < grid[i].size(); j++) {if(grid[i][j] == 0) continue;grid[i][j] = 0;if(check(grid)) return 1;grid[i][j] = 1;}}return 2;}
};
总结:
这题更像是一道思维题,当发现最多只要2步操作得时候,这题就AC了。这道题得时间复杂度为 O(n^4)
1569. 将子数组重新排序得到同一个二叉查找树的方案数
代码:
class Solution {
public:const long long mod = 1000000007;long long com[1001][1001];long long combine(int a , int b) {return com[a][b];}void dfs(vector<int>& nums , int L , int R , long long &mul) {if(R - L + 1 <= 2) return;vector<int> less , greater;for(int i = L + 1; i <= R; i++) {if(nums[i] < nums[L]) less.push_back(nums[i]);else greater.push_back(nums[i]);}mul *= combine(less.size() + greater.size() , greater.size());if(mul >= mod) mul %= mod;dfs(less , 0 , less.size() - 1 , mul);dfs(greater , 0 , greater.size() - 1 , mul);}int numOfWays(vector<int>& nums) {com[1][0] = com[1][1] = 1;for(int i = 2; i <= 1000; i++) {com[i][0] = 1;for(int j = 1; j <= i; j++) {com[i][j] = (com[i - 1][j] + com[i - 1][j - 1]) % mod;}}long long mul = 1;dfs(nums , 0 , nums.size() - 1, mul);return (mul - 1 + mod) % mod;}
};
34场双周赛
5492. 分割字符串的方案数
解题思路:
对于没有1的字符串,就是排列组合问题,一共有 种可能。
对于有1的字符串,若1的数量不能被3整除时,直接返回0。否则就是计算第一个字符串结尾和第二个字符开头有多少个0字符串再加1,再计算第二个字符串结尾和第三个字符串开发之间有多少个0字符串再加1。两数相乘即可得到答案
代码:
class Solution {
public:const int mod = 1000000007;int numWays(string s) {bool flag = true;long long res = 0;int num = 0;for(int i = 0; i < s.size(); i++) {if(s[i] == '1') {flag = false;num++;}}if(flag) {long long sz = s.size();res = (sz - 1) * (sz - 2) / 2;return res % mod;}if(num % 3 != 0) {return 0;}int both = num / 3;long long temp1 = 1 , temp2 = 1 , temp = 0;for(int i = 0; i < s.size(); i++) {if(s[i] == '1' && both) {both--;} else if(s[i] == '0' && !both) {temp++;} else if(s[i] == '1' && !both) {if(temp1 == 1) temp1 = temp + 1;else if(temp2 == 1) temp2 = temp + 1;temp = 0;both = num / 3 - 1;}}res = temp1 * temp2;res %= mod;return res;}
};
总结:
这题在我比赛时,死在了没有1的情况下,不知道如何算出,我直接使用加法进行计算。
5493. 删除最短的子数组使剩余数组有序
解题思路:
- 找到两端的有序子数组
- 合并两个数组成为一个新的有序数组,计算影响成为有序数组数据的数量
- 计算无序数组的数量
- 返回影响成为有序数组数据的数量+无序数组的数量
代码:
class Solution {
public:int findLengthOfShortestSubarray(vector<int>& arr) {int n = arr.size();int i = 0;for(; i < n - 1; i++) {if(arr[i] > arr[i + 1]) break;}int left = i;if(left == n - 1) return 0;i = n - 1;for(; i > 0; i--) {if(arr[i] < arr[i - 1]) break;}int right = i;if(right - left == n - 1) {if(arr[right] >= arr[left]) return n - 2;return n - 1;}if(arr[left] <= arr[right]) return right - left - 1;int l = 0 , r = right , cnt = 0;while(l < left + 1 && r < n) {if(arr[l] > arr[r]) {cnt++;l++;r++;} else {l++;}}return right - left - 1 + cnt;}
};
总结:
- left == n - 1,证明数组本身就是个有序数组,直接返回0
- right - left == n - 1,证明数组除开头尾就是一个反序数组。然后判断arr[right]和arr[left]
- 若arr[left]和arr[right]能组成一个有序数组,则返回n - 2
- 否则返回n - 1
- 当arr[left] <= arr[right],证明左端有序数组的结尾与右端有序数组的开头能组成有序数组,直接删除中间的无需数组即可
5494. 统计所有可行路径
解题思路:
每种求路径数量的问题都可以使用动态规划来解决。问题就是如何设置dp数组和函数逻辑。
dp[i][j]
表示当前起点为i
,剩余油量j
的总方案数。
因为这个路径可以重复走无数次,所以我们的结束条件就是不重复计算即可。
代码:
typedef long long ll;
int dp[105][205];
const int mod = 1e9 + 7;class Solution {
public:int dfs(vector<int>& locations , int start , int finish , int fuel) {if(dp[start][fuel] != -1) return dp[start][fuel];ll res = 0;if(start == finish) res++;int len = locations.size();for(int i = 0; i < len; i++) {int diff = abs(locations[i] - locations[start]);if(start == i) continue;if(fuel - diff >= 0) {res = (res + dfs(locations , i , finish , fuel - diff)) % mod;}}dp[start][fuel] = res % mod;return dp[start][fuel];}int countRoutes(vector<int>& locations, int start, int finish, int fuel) {memset(dp , -1 , sizeof(dp));return dfs(locations , start , finish , fuel);}
};
总结:
- 必须要在类内初始化一下,如果不初始化,默认数组中的数就为0,但是dp[start][fuel] == 0,可能会出现重复计算的情况
这题其实不难,或者说动态规划的题大部分都不难,主要是找到dp数组的参数设置,然后就是空间和时间的优化。这些都是动态规划中涉及的。
第205场周赛
1577. 数的平方等于两数乘积的方法数
解题思路:
直接用两个哈希表来存储数组中每个数的平方值的个数,最后根据nums1[i] * nums1[j]的值为索引值找到个数,nums2同理可得
代码:
class Solution {
public:int numTriplets(vector<int>& nums1, vector<int>& nums2) {map<long long , int> mli1 , mli2;int res = 0;for(auto i : nums1) mli1[(long long) 1 * i * i]++;for(auto i : nums2) mli2[(long long) 1 * i * i]++;for(int i = 0; i < nums1.size(); i++) {for(int j = i + 1; j < nums1.size(); j++) {res += mli2[(long long) 1 * nums1[i] * nums1[j]];}}for(int i = 0; i < nums2.size(); i++) {for(int j = i + 1; j < nums2.size(); j++) {res += mli1[(long long) 1 * nums2[i] * nums2[j]];}}return res;}
};
总结:
这题使用哈希表存储平方数值的个数方法解决,比赛时想到用的是递归方法,想得非常的复杂,其实是道水题
1578. 避免重复字母的最小删除成本
解题思路:
当遇到重复字母时,我们使用贪心思想,选择当前两个中的较小成本的字母进行”删除“。当“删除”的字母是i + 1时,因为i + 1可能会影响到后面的成本计算,所以把i + 1和 i 的成本交换一下,相当于删除的是永远是前面一个重复数,并且是成本较小的。
代码:
class Solution {
public:int minCost(string s, vector<int>& cost) {int res = 0 , n = s.size();for(int i = 0; i < n - 1; i++) {if(s[i] == s[i + 1]) {res += min(cost[i] , cost[i + 1]);if(cost[i] > cost[i + 1]) swap(cost[i] , cost[i + 1]);}}return res;}
};
总结:
这里的贪心思想如何转换成对于全局都适用的规律呢,就是swap(cost[i] , cost[i + 1])。当我们遇到3个或者多个相同的数时,我总是比较当前的两个,无法想到如何顾及到后面较小的成本值。这就是解决方法。
Leetcode周赛专题相关推荐
- C/C++描述 LeetCode 周赛 第199场周赛(阿里云专场)
C/C++描述 LeetCode 周赛 第199场周赛(阿里云专场) 大家好,我叫亓官劼(qí guān jié ),在CSDN中记录学习的点滴历程,时光荏苒,未来可期,加油~博主目前仅在CSDN ...
- [LeetCode周赛复盘] 第 314 场周赛20221009
[LeetCode周赛复盘] 第 314 场周赛20221009 一.本周周赛总结 二. [Easy] 6201. 找出前缀异或的原始数组 1. 题目描述 2. 思路分析 3. 代码实现 三.[Eas ...
- leetcode周赛5465. 子树中标签相同的节点数
leetcode周赛5465. 子树中标签相同的节点数 给你一棵树(即,一个连通的无环无向图),这棵树由编号从 0 到 n - 1 的 n 个节点组成,且恰好有 n - 1 条 edges .树的根节 ...
- 我也是LeetCode周赛“三道题选手”啦 第270场周赛
第270场周赛小结 我的Weekly Contest 270战况 什么是LeetCode周赛? show my code! 复盘解决Hard题 我的Weekly Contest 270战况 参加周赛有 ...
- [LeetCode周赛复盘] 第 89 场双周赛20221015
[LeetCode周赛复盘] 第 89 场双周赛20221015 一.本周周赛总结 二. [Easy] 6208. 有效时间的数目 1. 题目描述 2. 思路分析 3. 代码实现 三.[Medium] ...
- [LeetCode周赛复盘] 第 324 场周赛20221218
[LeetCode周赛复盘] 第 324 场周赛20221218 一.本周周赛总结 二. [Easy] 6265. 统计相似字符串对的数目 1. 题目描述 2. 思路分析 3. 代码实现 三.[Med ...
- [LeetCode周赛复盘] 第 310 场周赛20220911
[LeetCode周赛复盘] 第 310 场周赛20220911 一.本周周赛总结 二. [Easy] 6176. 出现最频繁的偶数元素 1. 题目描述 2. 思路分析 3. 代码实现 三.[Medi ...
- leetcode探索专题中的初级算法练习题(python代码+解题思路)
本文记录leetcode探索专题中的初级算法练习题,附python实现代码&解题思路,做题过程不免查阅网络资料,侵删~如有错误,欢迎指正交流! 目录 专题一:数组: 26.从排序数组中删除重复 ...
- 宝宝也能看懂的 leetcode 周赛 - 174 - 3
1339. 分裂二叉树的最大乘积 Hi 大家好,我是张小猪.欢迎来到『宝宝也能看懂』系列之 leetcode 周赛题解. 这里是第 174 期的第 3 题,也是题目列表中的第 1339 题 -- 『分 ...
最新文章
- 条件随机场CRF简介Introduction to Conditional Random Fields
- 使用Idea创建SpringCloud父子工程
- VTK:Utilities之Timer
- 开源纯C#工控网关+组态软件(五)从网关到人机界面
- JavaScript中的位置协议属性
- linux内核那些事之mmap_region流程梳理
- 淘宝直播应关注哪些方面?
- 怎么一键重装系统?装机大师一键重装图文教程
- python实现基于selenium的天猫淘宝秒杀,支持定金商品,自动付款
- 2018 年计算机语言排行榜,TIOBE:2018年11月编程语言排行榜
- Python网络爬虫精要
- 21.BOM的理解,常见的BOM对象你了解哪些?
- 【border相关】【P3426】 [POI2005]SZA-Template
- 固高jog运动和点位运动
- pull时出现错误及解决方法
- AD拼版工具 Embedded board array 进行PCB拼版注意事项
- [VOT15](2021CVPR)Alpha-Refine: Boosting Tracking Performance by Precise Bounding Box Estimation
- 兄弟姐妹们,有没有啥开源的项目能加一下我吗?
- 关于传奇聚灵珠Gom脚本的详细说明讲解
- 网络撮合交易的大市场
热门文章
- 微软文档外泄:Xbox 720、Kinect 2以及Kinect Glasses抢先看
- 雷林鹏:一个90后草根创业者的野蛮生长
- 数独游戏的两种编程思路+代码
- soap java实现_java使用soap方式简单实现webservice (二)
- 如何用python显示出所有能被17整除的数_怎样判定一个数能被17整除
- wps日期加减算天数_WPS表格计算这个月的剩余天数的公式
- php注册表唯一电脑,windows 注册表里注册自己的协议(原创)
- 详解CSS float属性
- java 密码检测_Java工具集-密码检测工具
- 【转载】iphone九宫格界面实现