跳转至

力扣第254场周赛

题一 作为子字符串出现在单词中的字符串数目

描述

给你一个字符串数组 patterns 和一个字符串 word ,统计 patterns 中有多少个字符串是 word 的子字符串。返回字符串数目。

子字符串 是字符串中的一个连续字符序列。

示例 1:

输入:patterns = ["a","abc","bc","d"], word = "abc" 输出:3 解释: - "a" 是 "abc" 的子字符串。 - "abc" 是 "abc" 的子字符串。 - "bc" 是 "abc" 的子字符串。 - "d" 不是 "abc" 的子字符串。 patterns 中有 3 个字符串作为子字符串出现在 word 中。 示例 2:

输入:patterns = ["a","b","c"], word = "aaaaabbbbb" 输出:2 解释: - "a" 是 "aaaaabbbbb" 的子字符串。 - "b" 是 "aaaaabbbbb" 的子字符串。 - "c" 不是 "aaaaabbbbb" 的字符串。 patterns 中有 2 个字符串作为子字符串出现在 word 中。 示例 3:

输入:patterns = ["a","a","a"], word = "ab" 输出:3 解释:patterns 中的每个字符串都作为子字符串出现在 word "ab" 中。

提示:

1 <= patterns.length <= 100 1 <= patterns[i].length <= 100 1 <= word.length <= 100 patterns[i] 和 word 由小写英文字母组成

思路

直接遍历判断。

代码

/**
 * @author mikusugar
 */
public class N1 {
    public int numOfStrings(String[] patterns, String word) {
        int res = 0;
        for (String str : patterns) {
            if (word.contains(str)) res++;
        }
        return res;
    }
}

题二 构造元素不等于两相邻元素平均值的数组

描述

给你一个 下标从 0 开始 的数组 nums ,数组由若干 互不相同的 整数组成。你打算重新排列数组中的元素以满足:重排后,数组中的每个元素都 不等于 其两侧相邻元素的 平均值 。

更公式化的说法是,重新排列的数组应当满足这一属性:对于范围 1 <= i < nums.length - 1 中的每个 i ,(nums[i-1] + nums[i+1]) / 2 不等于 nums[i] 均成立 。

返回满足题意的任一重排结果。

示例 1:

输入:nums = [1,2,3,4,5] 输出:[1,2,4,5,3] 解释: i=1, nums[i] = 2, 两相邻元素平均值为 (1+4) / 2 = 2.5 i=2, nums[i] = 4, 两相邻元素平均值为 (2+5) / 2 = 3.5 i=3, nums[i] = 5, 两相邻元素平均值为 (4+3) / 2 = 3.5 示例 2:

输入:nums = [6,2,0,9,7] 输出:[9,7,6,2,0] 解释: i=1, nums[i] = 7, 两相邻元素平均值为 (9+6) / 2 = 7.5 i=2, nums[i] = 6, 两相邻元素平均值为 (7+2) / 2 = 4.5 i=3, nums[i] = 2, 两相邻元素平均值为 (6+0) / 2 = 3

思路

乱搞过了,感觉有问题

代码

/**
 * @author mikusugar
 */
public class N2 {

    public int[] rearrangeArray(int[] nums) {
        for (int i=1;i<nums.length-1;i++){
            if(check(i,nums))continue;
            for (int k= nums.length-1;k>=i+1;k--){
                swap(i,k,nums);
                if(check(i,nums)&&check(i-1,nums))break;
                swap(i,k,nums);
            }
            if(check(i,nums))continue;
            for (int k=0;k<=i-1;k++){
                swap(k,i,nums);
                if(check(k-1,nums)&&check(k,nums)&&check(k+1,nums)&&check(i,nums)&&check(i-1,nums))break;
                swap(k,i,nums);
            }
        }
        return nums;
    }

    private void swap(int i,int j,int[] nums){
        int tar= nums[i];
        nums[i]=nums[j];
        nums[j]=tar;
    }
    private boolean check(int i, int[] nums) {
        if(i<=0||i>= nums.length-1)return true;
        return nums[i]*1.0!=(nums[i-1]+nums[i+1])/2.0;
    }
}

题三 数组元素的最小非零乘积

描述

给你一个正整数 p 。你有一个下标从 1 开始的数组 nums ,这个数组包含范围 [1, 2p - 1] 内所有整数的二进制形式(两端都 包含)。你可以进行以下操作 任意 次:

从 nums 中选择两个元素 x 和 y 。 选择 x 中的一位与 y 对应位置的位交换。对应位置指的是两个整数 相同位置 的二进制位。 比方说,如果 x = 1101 且 y = 0011 ,交换右边数起第 2 位后,我们得到 x = 1111 和 y = 0001 。

请你算出进行以上操作 任意次 以后,nums 能得到的 最小非零 乘积。将乘积对 109 + 7 取余 后返回。

注意:答案应为取余 之前 的最小值。

示例 1:

输入:p = 1 输出:1 解释:nums = [1] 。 只有一个元素,所以乘积为该元素。 示例 2:

输入:p = 2 输出:6 解释:nums = [01, 10, 11] 。 所有交换要么使乘积变为 0 ,要么乘积与初始乘积相同。 所以,数组乘积 1 * 2 * 3 = 6 已经是最小值。 示例 3:

输入:p = 3 输出:1512 解释:nums = [001, 010, 011, 100, 101, 110, 111] - 第一次操作中,我们交换第二个和第五个元素最左边的数位。 - 结果数组为 [001, 110, 011, 100, 001, 110, 111] 。 - 第二次操作中,我们交换第三个和第四个元素中间的数位。 - 结果数组为 [001, 110, 001, 110, 001, 110, 111] 。 数组乘积 1 * 6 * 1 * 6 * 1 * 6 * 7 = 1512 是最小乘积。

提示:

1 <= p <= 60

思路

最后一个数不变,把剩下的数一半变成1,一半变成11...110

不知道怎么证明。。。直觉。

具体求解用快速冥。

注意溢出

代码

/**
 * @author mikusugar
 */
public class N3 {

    private final static int MOD = (int) (1e9 + 7);

    public int minNonZeroProduct(int p) {

        long res = fastPow(2, p, MOD) - 1;
        long res1 = fastPow(fastPow(2, p, MOD) - 2, (fastPow(2, p) - 2) / 2, MOD);
        return (int) (res * res1 % MOD);

    }

    private long fastPow(long a, long b) {
        if (b == 0) return 1;
        long res = fastPow(a, b / 2);
        if (b % 2 == 1) return res * res * a;
        return res * res;
    }

    private long fastPow(long a, long b, long m) {
        if (b == 0) return 1;
        long res = fastPow(a, b / 2, m) % m;
        if (b % 2 == 1) return res * res % m * a % m;
        return res * res % m;
    }
}

题四 你能穿过矩阵的最后一天

描述

给你一个下标从 1 开始的二进制矩阵,其中 0 表示陆地,1 表示水域。同时给你 row 和 col 分别表示矩阵中行和列的数目。

一开始在第 0 天,整个 矩阵都是 陆地 。但每一天都会有一块新陆地被 水 淹没变成水域。给你一个下标从 1 开始的二维数组 cells ,其中 cells[i] = [ri, ci] 表示在第 i 天,第 ri 行 ci 列(下标都是从 1 开始)的陆地会变成 水域 (也就是 0 变成 1 )。

你想知道从矩阵最 上面 一行走到最 下面 一行,且只经过陆地格子的 最后一天 是哪一天。你可以从最上面一行的 任意 格子出发,到达最下面一行的 任意 格子。你只能沿着 四个 基本方向移动(也就是上下左右)。

请返回只经过陆地格子能从最 上面 一行走到最 下面 一行的 最后一天 。

示例 1:

输入:row = 2, col = 2, cells = [[1,1],[2,1],[1,2],[2,2]] 输出:2 解释:上图描述了矩阵从第 0 天开始是如何变化的。 可以从最上面一行到最下面一行的最后一天是第 2 天。 示例 2:

输入:row = 2, col = 2, cells = [[1,1],[1,2],[2,1],[2,2]] 输出:1 解释:上图描述了矩阵从第 0 天开始是如何变化的。 可以从最上面一行到最下面一行的最后一天是第 1 天。 示例 3:

输入:row = 3, col = 3, cells = [[1,2],[2,1],[3,3],[2,2],[1,1],[1,3],[2,3],[3,2],[3,1]] 输出:3 解释:上图描述了矩阵从第 0 天开始是如何变化的。 可以从最上面一行到最下面一行的最后一天是第 3 天。

提示:

2 <= row, col <= 2 * 10^4 4 <= row * col <= 2 * 10^4 cells.length == row * col 1 <= ri <= row 1 <= ci <= col cells 中的所有格子坐标都是 唯一 的。

思路

一开始的思路是 动态规划,想错了🙅‍♂️,推不出公式来。

题目意思也理解错了,我一开始以为移动一次要一天。。。

正确思路:

二分+BFS

以后看到这种求最值的问题要想想二分能不能用。

代码

/**
 * @author mikusugar
 */
public class N4 {

    public int latestDayToCross(int row, int col, int[][] cells) {
        int[][] book = new int[row + 2][col + 2];
        for (int i = 0; i < cells.length; i++) {
            book[cells[i][0]][cells[i][1]] = i + 1;
        }

        int left = 0, right = cells.length - 1;
        int res = 0;

        while (left <= right) {
            int day = (left + right) / 2;
            if (check(day, book, row, col)) {
                left = day + 1;
                res = day;
            } else right = day - 1;
        }
        return res;
    }

    private boolean check(int day, int[][] book, int row, int col) {
        Queue<int[]> queue = new ArrayDeque<>();

        boolean[][] been = new boolean[book.length][book[0].length];
        for (int i = 1; i <= col; i++) {
            if (book[1][i] <= day) continue;
            queue.add(new int[]{1, i});
            been[1][i]=true;
        }

        while (!queue.isEmpty()) {
            final int[] cur = queue.poll();
            if (cur[0] == row) return true;
            for (int[] next : NEXTS) {
                int i = cur[0] + next[0];
                int j = cur[1] + next[1];
                if (i < 1 || i > row || j < 1 || j > col || day >= book[i][j] || been[i][j])
                    continue;
                been[i][j]=true;
                queue.add(new int[]{i, j});
            }
        }

        return false;
    }

    private final static int[][] NEXTS = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};

}