• LeetCode Weekly Contest 289


    题目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

    思路

    题目难点有两个

    1. 如果确定尾随0的个数
    2. 怎么确定是尾随最长的路径

    对于第一点,我们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;
        }
    }
    
  • 相关阅读:
    chrome浏览页面常用快捷键 && 常见的HTTP状态码
    hasCode详解
    队例初始化问题(Queue)
    新手问题--双链表最后一个节点无法删除问题
    高级排序--快速排序
    高级排序--归并排序
    高级排序--希尔排序
    简单排序--插入排序
    简单排序--选择排序
    简单排序--冒泡排序
  • 原文地址:https://www.cnblogs.com/Asimple/p/16155483.html
Copyright © 2020-2023  润新知