算法提升——LeetCode383场周赛总结

周赛题目

边界上的蚂蚁

边界上有一只蚂蚁,它有时向左走,有时向右走。

给你一个非零整数数组nums。蚂蚁会按顺序读取nums中的元素,从第一个元素开始直到结束。每一步,蚂蚁会根据当前元素的值移动:

如果nums[i]<0,向左移动-nums[i]单位。

如果nums[i]>0,向右移动nums[i]单位。

返回蚂蚁返回到边界上的次数。

解题思路

本题是一道简单题,只要看懂题目,知道是求每次+nums[i]后的值为0的次数即可。

java 复制代码
class Solution {
    public int returnToBoundaryCount(int[] nums) {
        int result=0;
        int target=0;
        for(int tem:nums){
            target+=tem;
            if (target==0){
                result++;
            }
        }
        return result;
    }
}

将单词恢复初始状态所需的最短时间 I

给你一个下标从0开始的字符串word和一个整数k。

在每一秒,你必须执行以下操作:

移除word的前k个字符。

在word的末尾添加k个任意字符。

注意添加的字符不必和移除的字符相同。但是,必须在每一秒钟都执行两种操作。

返回将word恢复到其初始状态所需的最短时间(该时间必须大于零)。

解题思路

本题需要至少切割1次,最多切割len/k向上取整次必然可以恢复。因为每次切割后面是拼接任意字符,所以只需要考虑切割后剩余的字符串是不是原来word的开头即可。

java 复制代码
class Solution {
    public int minimumTimeToInitialState(String word, int k) {
        int result=0;
        int start=k;
        int len=word.length();
        int sum = (int) Math.ceil((double) len / k);
        while(start<len){
            result++;
            if (word.indexOf(word.substring(start))==0){
                return result;
            }
            start+=k;
        }
        return sum;
    }
}

找出网格的区域平均强度

给你一个下标从0开始、大小为mxn的网格image,表示一个灰度图像,其中image[i][j]表示在范围[0...255]内的某个像素强度。另给你一个非负整数threshold。

如果image[a][b]和image[c][d]满足|a-c|+|b-d|==1,则称这两个像素是相邻像素。

区域是一个3x3的子网格,且满足区域中任意两个相邻像素之间,像素强度的绝对差小于或等于threshold。

区域内的所有像素都认为属于该区域,而一个像素可以属于多个区域。

你需要计算一个下标从0开始、大小为mxn的网格result,其中result[i][j]是image[i][j]所属区域的平均强度,向下取整到最接近的整数。如果image[i][j]属于多个区域,result[i][j]是这些区域的"取整后的平均强度"的平均值,也向下取整到最接近的整数。如果image[i][j]不属于任何区域,则result[i][j]等于image[i][j]。

返回网格result。

解题思路

遍历所有3*3的子网格,如果存在差值超过threshwold则跳过;如果合法则计算平均值。

java 复制代码
public class Solution {
    public int[][] resultGrid(int[][] a, int threshold) {
        int m = a.length;
        int n = a[0].length;
        int[][] result = new int[m][n];
        int[][] cnt = new int[m][n];
        for (int i = 2; i < m; i++) {
            next: // 定义跳出标签
            for (int j = 2; j < n; j++) {
                // 检查左右相邻格子
                for (int x = i - 2; x <= i; x++) {
                    if (Math.abs(a[x][j - 2] - a[x][j - 1]) > threshold || Math.abs(a[x][j - 1] - a[x][j]) > threshold) {
                        continue next; // 不合法,跳出双重循环
                    }
                }

                // 检查上下相邻格子
                for (int y = j - 2; y <= j; ++y) {
                    if (Math.abs(a[i - 2][y] - a[i - 1][y]) > threshold || Math.abs(a[i - 1][y] - a[i][y]) > threshold) {
                        continue next; // 不合法,跳出双重循环
                    }
                }

                // 合法,计算 3x3 子网格的平均值
                int avg = 0;
                for (int x = i - 2; x <= i; x++) {
                    for (int y = j - 2; y <= j; y++) {
                        avg += a[x][y];
                    }
                }
                avg /= 9;

                // 更新 3x3 子网格内的 result
                for (int x = i - 2; x <= i; x++) {
                    for (int y = j - 2; y <= j; y++) {
                        result[x][y] += avg; // 先累加,最后再求平均值
                        cnt[x][y]++;
                    }
                }
            }
        }

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (cnt[i][j] == 0) { // (i,j) 不属于任何子网格
                    result[i][j] = a[i][j];
                } else {
                    result[i][j] /= cnt[i][j]; // 求平均值
                }
            }
        }
        return result;
    }
}

将单词恢复初始状态所需的最短时间 II

给你一个下标从0开始的字符串word和一个整数k。

在每一秒,你必须执行以下操作:

移除word的前k个字符。

在word的末尾添加k个任意字符。

注意添加的字符不必和移除的字符相同。但是,必须在每一秒钟都执行两种操作。

返回将word恢复到其初始状态所需的最短时间(该时间必须大于零)。

解题思路

这道题和第二道题截图思路是一样的,但是不能再用JDK自带的方法区解,会超时。从第二道题中我们能看出来本题的本质上计算s的后缀和s的最长公共前缀的长度,即使用哦个扩展KMP判断,如果最长公共前缀的长度大于等于后缀长度,说明操作可以恢复到初始值。

java 复制代码
class Solution {
    public int minimumTimeToInitialState(String S, int k) {
        char[] s = S.toCharArray();
        int n = s.length;
        int[] z = new int[n];
        int l = 0, r = 0;
        for (int i = 1; i < n; i++) {
            if (i <= r) {
                z[i] = Math.min(z[i - l], r - i + 1);
            }
            while (i + z[i] < n && s[z[i]] == s[i + z[i]]) {
                l = i;
                r = i + z[i];
                z[i]++;
            }
            if (i % k == 0 && z[i] >= n - i) {
                return i / k;
            }
        }
        return (n - 1) / k + 1;
    }
}

总结

通过总结周赛的解法,学习到自己还有很多不足。同时也学到了一个平时开发不会用到的操作,就是如何用continue跳出双重循环。

后续因为本次题目中所使用到的KMP算法不甚了解,后续需要学习该算法,并输出一篇总结笔记。

相关推荐
初晴~18 分钟前
【Redis分布式锁】高并发场景下秒杀业务的实现思路(集群模式)
java·数据库·redis·分布式·后端·spring·
黑胡子大叔的小屋1 小时前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计
ThisIsClark1 小时前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
火星机器人life2 小时前
基于ceres优化的3d激光雷达开源算法
算法·3d
虽千万人 吾往矣2 小时前
golang LeetCode 热题 100(动态规划)-更新中
算法·leetcode·动态规划
雷神乐乐2 小时前
Spring学习(一)——Sping-XML
java·学习·spring
arnold662 小时前
华为OD E卷(100分)34-转盘寿司
算法·华为od
小林coding3 小时前
阿里云 Java 后端一面,什么难度?
java·后端·mysql·spring·阿里云
V+zmm101343 小时前
基于小程序宿舍报修系统的设计与实现ssm+论文源码调试讲解
java·小程序·毕业设计·mvc·ssm
ZZTC3 小时前
Floyd算法及其扩展应用
算法