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

周赛题目

边界上的蚂蚁

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

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

如果nums[i]<0,向左移动-nums[i]单位。
如果nums[i]>0,向右移动nums[i]单位。
返回蚂蚁返回到边界上的次数。

解题思路

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

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的开头即可。

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则跳过;如果合法则计算平均值。

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判断,如果最长公共前缀的长度大于等于后缀长度,说明操作可以恢复到初始值。

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

相关推荐

  1. 算法提升——LeetCode383总结

    2024-02-05 11:44:09       56 阅读
  2. 算法提升——LeetCode382 总结

    2024-02-05 11:44:09       49 阅读
  3. 算法提升——LeetCode385总结

    2024-02-05 11:44:09       48 阅读
  4. 算法提升——LeetCode122总结

    2024-02-05 11:44:09       65 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-05 11:44:09       91 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-05 11:44:09       97 阅读
  3. 在Django里面运行非项目文件

    2024-02-05 11:44:09       78 阅读
  4. Python语言-面向对象

    2024-02-05 11:44:09       88 阅读

热门阅读

  1. 力扣_字符串3—通配符匹配

    2024-02-05 11:44:09       37 阅读
  2. prettier和eslint冲突怎么解决?

    2024-02-05 11:44:09       57 阅读
  3. LINUX 日常使用命令

    2024-02-05 11:44:09       40 阅读
  4. float与double区别

    2024-02-05 11:44:09       51 阅读
  5. gerrit(1) | gerrit 简介

    2024-02-05 11:44:09       55 阅读
  6. PHP三级分类数据处理

    2024-02-05 11:44:09       45 阅读