题目1 计算字符串的数字和
题目
给你一个由若干数字(0 - 9)组成的字符串 s ,和一个整数。
如果 s 的长度大于 k ,则可以执行一轮操作。在一轮操作中,需要完成以下工作:
将 s 拆分 成长度为 k 的若干 连续数字组 ,使得前 k 个字符都分在第一组,接下来的 k 个字符都分在第二组,依此类推。注意,最后一个数字组的长度可以小于 k 。
用表示每个数字组中所有数字之和的字符串来 替换 对应的数字组。例如,"346" 会替换为 "13" ,因为 3 + 4 + 6 = 13 。
合并 所有组以形成一个新字符串。如果新字符串的长度大于 k 则重复第一步。
返回在完成所有轮操作后的 s 。
示例 1:
输入:s = "11111222223", k = 3
输出:"135"
解释:
- 第一轮,将 s 分成:"111"、"112"、"222" 和 "23" 。
接着,计算每一组的数字和:1 + 1 + 1 = 3、1 + 1 + 2 = 4、2 + 2 + 2 = 6 和 2 + 3 = 5 。
这样,s 在第一轮之后变成 "3" + "4" + "6" + "5" = "3465" 。 - 第二轮,将 s 分成:"346" 和 "5" 。
接着,计算每一组的数字和:3 + 4 + 6 = 13 、5 = 5 。
这样,s 在第二轮之后变成 "13" + "5" = "135" 。
现在,s.length <= k ,所以返回 "135" 作为答案。
示例 2:
输入:s = "00000000", k = 3
输出:"000"
解释:
将 "000", "000", and "00".
接着,计算每一组的数字和:0 + 0 + 0 = 0 、0 + 0 + 0 = 0 和 0 + 0 = 0 。
s 变为 "0" + "0" + "0" = "000" ,其长度等于 k ,所以返回 "000" 。
提示:
1 <= s.length <= 100
2 <= k <= 100
s 仅由数字(0 - 9)组成。
思路
简单的模拟题,按照题目意思模拟即可,由于整个过程是一个重复的过程,可以使用递归减少代码量。
AC代码
点击查看代码
class Solution {
public String digitSum(String s, int k) {
int len = s.length();
if( len<=k ) {
return s;
}
String res = "";
for(int i=0; i<len; ) {
int j = 0;
int sum = 0;
while( j<k && i<len ) {
sum += (int) s.charAt(i) - '0';
j ++;
i ++;
}
res = res + sum;
}
return digitSum(res, k);
}
}
题目2 完成所有任务需要的最少轮数
题目
给你一个下标从 0 开始的整数数组 tasks ,其中 tasks[i] 表示任务的难度级别。在每一轮中,你可以完成 2 个或者 3 个 相同难度级别 的任务。
返回完成所有任务需要的 最少 轮数,如果无法完成所有任务,返回 -1 。
示例 1:
输入:tasks = [2,2,3,3,2,4,4,4,4,4]
输出:4
解释:要想完成所有任务,一个可能的计划是:
- 第一轮,完成难度级别为 2 的 3 个任务。
- 第二轮,完成难度级别为 3 的 2 个任务。
- 第三轮,完成难度级别为 4 的 3 个任务。
- 第四轮,完成难度级别为 4 的 2 个任务。
可以证明,无法在少于 4 轮的情况下完成所有任务,所以答案为 4 。
示例 2:
输入:tasks = [2,3,3]
输出:-1
解释:难度级别为 2 的任务只有 1 个,但每一轮执行中,只能选择完成 2 个或者 3 个相同难度级别的任务。因此,无法完成所有任务,答案为 -1 。
提示:
1 <= tasks.length <= 10^5
1 <= tasks[i] <= 10^9
思路
看到题目的最少二字,第一反应就是贪心算法。按照贪心算法如果需要使完成任务的轮数最少,那么对于任务难度相同的任务就需要每次都完成3次,最后可能会有剩余1、2,剩余2次,可以直接完成,而剩余1次的时候,则可以加上上一次完成的3次,变成完成两个2次。当然如果本身就只有一次,那就是不能完成任务了,也就是可以推算出对于有相同难度的n个任务,有如下的规律:
1、n==1 任务无法完成,返回-1 2、n>1 任务完成次数为 n/3 + (n%3==0?0:1)
AC代码
点击查看代码
class Solution {
public int minimumRounds(int[] tasks) {
int len = tasks.length;
if( len < 2 ) {
return -1;
}
Arrays.sort(tasks);
int res = 0;
for(int i=0; i<len; ) {
int task = tasks[i];
int j = i + 1;
int cnt = 1;
while( j<len && tasks[j]==task) {
j ++;
cnt ++;
}
if( cnt == 1 ) {
return -1;
}
res += cnt/3;
int m = cnt % 3;
if(m!=0 ) {
res ++;
}
i = j;
}
return res;
}
}
题目3 转角路径的乘积中最多能有几个尾随零
题目
给你一个二维整数数组 grid ,大小为 m x n,其中每个单元格都含一个正整数。
转角路径 定义为:包含至多一个弯的一组相邻单元。具体而言,路径应该完全 向水平方向 或者 向竖直方向 移动过弯(如果存在弯),而不能访问之前访问过的单元格。在过弯之后,路径应当完全朝 另一个 方向行进:如果之前是向水平方向,那么就应该变为向竖直方向;反之亦然。当然,同样不能访问之前已经访问过的单元格。
一条路径的 乘积 定义为:路径上所有值的乘积。
请你从 grid 中找出一条乘积中尾随零数目最多的转角路径,并返回该路径中尾随零的数目。
注意:
水平 移动是指向左或右移动。
竖直 移动是指向上或下移动。
示例 1:
输入:grid = [[23,17,15,3,20],[8,1,20,27,11],[9,4,6,2,21],[40,9,1,10,6],[22,7,4,5,3]]
输出:3
解释:左侧的图展示了一条有效的转角路径。
其乘积为 15 * 20 * 6 * 1 * 10 = 18000 ,共计 3 个尾随零。
可以证明在这条转角路径的乘积中尾随零数目最多。
中间的图不是一条有效的转角路径,因为它有不止一个弯。
右侧的图也不是一条有效的转角路径,因为它需要重复访问已经访问过的单元格。
示例 2:
输入:grid = [[4,3,2],[7,6,1],[8,8,8]]
输出:0
解释:网格如上图所示。
不存在乘积含尾随零的转角路径。
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 10^5
1 <= m * n <= 10^5
1 <= grid[i][j] <= 1000
思路
题目难点有两个
- 如果确定尾随0的个数
- 怎么确定是尾随最长的路径
对于第一点,我们10分解质因数为2*5,也就是说尾随0的个数其实是取决于各个数中2、5的质因数的个数。
对于第二点,第一反应想到的就是搜索,看题目的范围好像应该也是可以的,竞赛中没有注意到 n*m<10^5,所以觉得搜索不可行,可以尝试一下。第二种方式是,我们仔细研究下题目,其实这个路径最终都是取的某一列和某一行相交,只要能计算出每行和每列的尾随零个数,然后两个for循环去找对于第i行和第j列相交时,四个方向的最大尾随零个数,比较考验代码功力。
题目4 相邻字符不同的最长路径
题目
给你一棵 树(即一个连通、无向、无环图),根节点是节点 0 ,这棵树由编号从 0 到 n - 1 的 n 个节点组成。用下标从 0 开始、长度为 n 的数组 parent 来表示这棵树,其中 parent[i] 是节点 i 的父节点,由于节点 0 是根节点,所以 parent[0] == -1 。
另给你一个字符串 s ,长度也是 n ,其中 s[i] 表示分配给节点 i 的字符。
请你找出路径上任意一对相邻节点都没有分配到相同字符的 最长路径 ,并返回该路径的长度。
示例 1:
输入:parent = [-1,0,0,1,1,2], s = "abacbe"
输出:3
解释:任意一对相邻节点字符都不同的最长路径是:0 -> 1 -> 3 。该路径的长度是 3 ,所以返回 3 。
可以证明不存在满足上述条件且比 3 更长的路径。
示例 2:
输入:parent = [-1,0,0,0], s = "aabc"
输出:3
解释:任意一对相邻节点字符都不同的最长路径是:2 -> 0 -> 3 。该路径的长度为 3 ,所以返回 3 。
提示:
n == parent.length == s.length
1 <= n <= 10^5
对所有 i >= 1 ,0 <= parent[i] <= n - 1 均成立
parent[0] == -1
parent 表示一棵有效的树
s 仅由小写英文字母组成
思路
按照题目所说构建出图,然后对构建出的图进行搜索,注意最长路径的保存。难点在于图的构建,DFS的剪枝,竞赛中超时了,竞赛后参考大佬的代码才写出来的AC代码。
AC代码
点击查看代码
class Solution {
int res = 0;
ArrayList <Integer> child[];
private int DFS(int node, String s) {
int num = 0;
int sec = 0;
for(int nextNode : child[node]) {
int tmp = DFS(nextNode, s);
if(s.charAt(nextNode)==s.charAt(node)) {
continue;
}
if(tmp > num) {
sec = num;
num = tmp;
} else if(tmp > sec) {
sec = tmp;
}
}
res = Math.max(res, num+sec+1);
return num + 1;
}
public int longestPath(int[] parent, String s) {
int n = parent.length;
child = new ArrayList[n];
for(int i = 0; i < n; i++) {
child[i] = new ArrayList();
}
for(int i = 1; i < n; i++) {
child[parent[i]].add(i);
}
DFS(0, s);
return res;
}
}