5492. 分割字符串的方案数 #组合公式 #乘法原理 #区间分割

题目链接

题意

给定01二进制串\(s\),可将\(s\)分割为三个非空 字符串\(s_1,s_2,s_3\),即(\(s_1+s_2+s_3=s\))。现要你求出分割\(s\)的方案数,保证\(s_1,s_2,s_3\)中字符1的数目相同(对\(1e9+7\)取模),他们的长度不一定相等

分析

举个例子,01100011000101串,可以知道三个子串必须包含2个'1',我们观察到左子串的界限,可以如下划分:011|000110001010110|001100010101100|011000101011000|11000101,共四种划分方案;同理对于右子串,共有四种划分方案。当我们将左右子串由于中间子串的间隔,使得左右子串的确定不会相互影响,同时中间子串也相应确定下来,通过乘法原理,总方案数=左子串划分方案数\(\times\)右子串划分方案数=16。

然而,别忘了诸如00000等只包含'0'的串,三子串的划分确定会相互影响,比如0|000|0000|0|0等,此时我们可以用高中所学排列组合的“挡板法”确定下来,即串长为\(n\),有\(n-1\)空位,可以插入两个挡板,即\(C^2_{n-1}\)。

typedef long long ll;
class Solution {
private:
int sum[100005];
const int MOD = 1e9 + 7;
public:
int numWays(string s) {
int n = s.size();
for (int i = 0; i < n; i++) //利用前缀和统计1的数目
sum[i + 1] = sum[i + 1 - 1] + (s[i] == '1');
if(sum[n] == 0){ //特判全部为0的串
ll ans = (ll)(n - 1) * (ll)(n - 2) / (ll)2;
return ans % MOD;
}
if(sum[n] % 3 != 0) return 0; //特判不含有3的整数倍的串,无法分割
else{
int diff = sum[n] / 3; //确定每个子串中的'1'数量
ll a = 0, b = 0;
for (int i = 1; i <= n - 2; i++) //确定左子串可拓展的长度
if(sum[i] == diff) a++;
for (int i = n; i >= 2; i--) //确定右子串可拓展的长度
if(sum[n] - sum[i - 1] == diff) b++;
ll ans = (a % MOD) * (b % MOD); //乘法原理
return ans % MOD;
}
}
};

5493. 删除最短的子数组使剩余数组有序 #归并排序 #区间分割

题目链接

题意

给定整数数组arr ,你需要删除一个子数组(原数组中连续的一个子序列,可以为空),使得arr中剩下的元素是 非递减的。现要你求出满足题目要求的最短子数组的长度。

分析

感谢@Liuyh思路。

题目要求只能删除一个子数组,也就说子数组内部存在一小段是非递减的,但也必须要删去。一般地,我们一定是从数组中间部分进行删除(只删除左部分或只删除右部分属于退化情况),即[....|XXXX|....](X表示要删除的部分)。 删除中间的子数组(并不代表最终删除子数组),意味着剩余前后两个子数组都符合非递减,这一操作需要前后两个指针,分别将两数组边界确定下来。代码中左子数组为[0, lo],而右子数组为[hi, len-1]。比如原数组[1,2,3,10,4,2,3,5],确定出左子数组 [1,2,3,10]lo指向10,右子数组[2, 3, 5]。中间数组删除长度为\(hi-lo+1\)

现在我们要合并上述两个子数组,需要用到归并排序的思想,一旦发现右子数组比左子数组还大的元素,其中一个元素给舍弃掉(无需考虑是删除左数组的还是右数组的)。举个例子:

  • [1,2,3,10][2,3,5]
  • 由于1<2,此时[2,3,10][2,3,5]
  • 由于2<=2,此时[3,10][2,3,5]
  • 由于3>2,舍弃右子数组的2,左子数组跳过3ans++,此时[10][3,5]
  • 由于10>3,舍弃10,得到 [][5],算法结束。
class Solution {
public:
int findLengthOfShortestSubarray(vector<int>& arr) {
int lo = 0, len = arr.size(), hi = arr.size() - 1;
if(len == 1) return 0; //特判:一个元素就无需删除了
while(lo + 1 < len && arr[lo] <= arr[lo + 1]) lo++;
//开始分割,确定左区间的右端点,注意,是往后递推,这样能够保证lo最终指向的依然是非降左子序列的右端点
if(lo + 1 == len) return 0; //说明原数组是个非降序列,直接返回0
while(lo < hi && arr[hi - 1] <= arr[hi]) hi--;
if(hi == lo && hi == 0) return len - 1; //说明原数组是完全递减区间 int ans = hi - lo - 1; //统计分割出来的区间
int i = 0, j = hi; while(i <= lo && j < len){ //合并区间
if(arr[i] <= arr[j]) i++; //以左序列为基准
else if(arr[i] > arr[j]){ //因为题目要求从左至右递增
i++; j++;//注意!一定是两个指针同时前进,因为你不知道哪个子数组影响最终结果
ans++;
}
}
return ans;
}
};

5494. 统计所有可行路径 #记忆化搜索

题目链接

题意

有若干个城市,第i个城市有location[i]值。给定你城市出发起点start、目的地城市finish、初始汽油总量fuel。每当你从城市j移动到城市i时,消耗的油量为|location[j] - location[i]|。你要保证剩余的油量非负,方能移动到其他城市。同时,你可以经过任意城市超过一次(包括startfinish)。现要你求出从startfinish可能路径的数目(需取模)

分析

观察到数据范围\(fuel\leq200\)及\(locations.len\leq100\),直接记忆化搜索即可。但注意,尽管你此时到达了finish城市,只要你油量足够,仍能够移动到其他城市。

dp[i][j]表示当前起点为i,剩余油量j的总方案数。

要注意,我直接把dp数组放到全局变量的时候,出锅了不少qaq,别忘了在类内要对这个全局变量初始化一下,同时记忆化搜索一般赋值为-1较为稳妥。

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 ans = 0; int len = locations.size();
if(start == finish) ans++;
for (int i = 0; i < len; i++){
int diff = abs(locations[i] - locations[start]);
if(start == i) continue;
if(fuel - diff >= 0){
ans = (ans + dfs(locations, i, finish, fuel - diff)) % MOD;
}
}
dp[start][fuel] = (ans % 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);
}
};

LeetCode双周赛#34的更多相关文章

  1. leetcode 双周赛9 进击的骑士

    一个坐标可以从 -infinity 延伸到 +infinity 的 无限大的 棋盘上,你的 骑士 驻扎在坐标为 [0, 0] 的方格里. 骑士的走法和中国象棋中的马相似,走 “日” 字:即先向左(或右 ...

  2. leetcode 双周赛9 找出所有行中最小公共元素

    给你一个矩阵 mat,其中每一行的元素都已经按 递增 顺序排好了.请你帮忙找出在所有这些行中 最小的公共元素. 如果矩阵中没有这样的公共元素,就请返回 -1. 示例: 输入:mat = [[,,,,] ...

  3. [每日一题2020.06.16] leetcode双周赛T3 5423 找两个和为目标值且不重叠的子数组 DP, 前缀和

    题目链接 给你一个整数数组 arr 和一个整数值 target . 请你在 arr 中找 两个互不重叠的子数组 且它们的和都等于 target .可能会有多种方案,请你返回满足要求的两个子数组长度和的 ...

  4. LeetCode双周赛#36

    1604. 警告一小时内使用相同员工卡大于等于三次的人 题目链接 题意 给定两个字符串数组keyName和keyTime,分别表示名字为keytime[i]的人,在某一天内使用员工卡的时间(格式为24 ...

  5. LeetCode双周赛#35

    1589. 所有排列中的最大和 #差分 #贪心 题目链接 题意 给定整数数组nums,以及查询数组requests,其中requests[i] = [starti, endi] .第i个查询求 num ...

  6. LeetCode双周赛#33 题解

    5480. 可以到达所有点的最少点数目 #贪心 题目链接 题意 给定有向无环图,编号从0到n-1,一个边集数组edges(表示从某个顶点到另一顶点的有向边),现要找到最小的顶点集合,使得从这些点出发, ...

  7. Leetcode 双周赛#32 题解

    1540 K次操作转变字符串 #计数 题目链接 题意 给定两字符串\(s\)和\(t\),要求你在\(k\)次操作以内将字符串\(s\)转变为\(t\),其中第\(i\)次操作时,可选择如下操作: 选 ...

  8. LeetCode第8场双周赛(Java)

    这次我只做对一题. 原因是题目返回值类型有误,写的是 String[] ,实际上应该返回 List<String> . 好吧,只能自认倒霉.就当涨涨经验. 5068. 前后拼接 解题思路 ...

  9. LeetCode 第 15 场双周赛

    1287.有序数组中出现次数超过25%的元素 1288.删除被覆盖区间 1286.字母组合迭代器 1289.下降路径最小和 II 下降和不能只保留原数组中最小的两个,hacked. 1287.有序数组 ...

随机推荐

  1. D. Road to Post Office 解析(思維)

    Codeforce 702 D. Road to Post Office 解析(思維) 今天我們來看看CF702D 題目連結 題目 略,請直接看原題. 前言 原本想說會不會也是要列式子解或者二分搜,沒 ...

  2. python基础二:循环

    python 中循环的方式有两种: 一,for 循环  单向循环 可以用来遍历字符串,列表,元组,字典等 for value in 被遍历对象: print(value) 遍历字典dict的时候稍有不 ...

  3. python常用模块numpy解析(详解)

    numpy模块 关注公众号"轻松学编程"了解更多. 以下命令都是在浏览器中输入. cmd命令窗口输入:jupyter notebook 后打开浏览器输入网址http://local ...

  4. 我叫MongoDb,不懂我的看完我的故事您就入门啦!

    这是mongo基础篇,后续会连续更新4篇 大家好我叫MongoDb,自从07年10月10gen团队把我带到这个世界来,我已经13岁多啦,现在越来越多的小伙伴在拥抱我,我很高兴.我是NoSQL大家族的一 ...

  5. 知识管理——得到CEO脱不花女士的一次分享

    知识管理--得到CEO脱不花女士的一次分享 近日,公司举办了一场"CKO首席知识官"研讨会,邀请到了得到APP的CEO脱不花女士做了一场精彩的分享,让我深受启发. 分享内容围绕3个 ...

  6. Python列表排序方法汇总,超详细!

    1. 修改原列表,不创建新列表的排序 1 a = [3, 2, 8, 4, 6] 2 print(id(a)) # 2180873605704 3 a.sort() # 默认升序 4 print(a) ...

  7. lvs负载简介,原理,常见使用案例及Keepalived高可用

    Lvs简介 基础概念 LVS(Linux Virtual Server)即Linux虚拟服务器,是由张文嵩博士主导的开源负载均衡项目,目前LVS已经被集成到Linux内核模块中(2.6及以上版本内核) ...

  8. 执行 yarn init报错,如何解决?

    安装yarn以后执行yarn init 命令来初始化项目 报错如下所示: 解决方法: 1.先用npm init初始化项目 在初始化的最后一步 is this ok(yes)? 输入yes回车后,可能会 ...

  9. 第05组 Alpha冲刺 (2/6)(组长)

    .th1 { font-family: 黑体; font-size: 25px; color: rgba(0, 0, 255, 1) } #ka { margin-top: 50px } .aaa11 ...

  10. offsetWidth与offsetHeight

    HTMLElement.offsetWidth 是一个只读属性,返回一个元素的布局宽度.一个典型的(译者注:各浏览器的offsetWidth可能有所不同)offsetWidth是测量包含元素的边框(b ...