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

周赛题目

边界上的蚂蚁

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

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

如果numsi<0,向左移动-numsi单位。

如果numsi>0,向右移动numsi单位。

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

解题思路

本题是一道简单题,只要看懂题目,知道是求每次+numsi后的值为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,表示一个灰度图像,其中imageij表示在范围0...255内的某个像素强度。另给你一个非负整数threshold。

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

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

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

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

返回网格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算法不甚了解,后续需要学习该算法,并输出一篇总结笔记。

相关推荐
Peter(阿斯拉)3 分钟前
[Android]_[中级]_[如何创建MVVM架构原型]
android·java·架构·mvvm·viewmodel
地瓜伯伯16 分钟前
从MESI缓存一致性协议讲透synchronized的底层
java·spring boot·spring·spring cloud·微服务·springcloud
叫我:松哥24 分钟前
基于Python flask的中学可控智能命题系统设计与实现,整合遗传算法、DeepSeek 大模型及数据库技术构建一体化应用
数据库·人工智能·python·算法·机器学习·flask·遗传算法
Devin~Y25 分钟前
大厂 Java 面试实录:从音视频内容社区到 AI RAG 的全链路技术设计
java·spring boot·redis·spring cloud·微服务·kafka·音视频
CoderYanger29 分钟前
A.每日一题:3612. 用特殊操作处理字符串 I
java·程序人生·leetcode·面试·职场和发展·学习方法·改行学it
黎阳之光35 分钟前
黎阳之光透明大楼:实景孪生重构智慧建筑全新范式
人工智能·物联网·算法·安全·数字孪生
承渊政道37 分钟前
飞算JavaAI 智能引导背后的多 Agent 协作机制解析:从老旧 Java 后台升级到可运行工程
java·开发语言·spring boot·安全·intellij-idea·软件工程·ai编程
旖-旎2 小时前
《LeetCode 130 被围绕的区域 FloodFill DFS 解法》
c++·算法·深度优先·力扣·floodfill
林森lsjs2 小时前
斐波那契数列的 N 种解法:从递归到动态规划的优化之路【算法思考】
算法·动态规划
唐青枫2 小时前
Java Flyway 实战指南:用 SQL 脚本管理数据库版本
java