Leetcode之第299场周赛小记

小记

本篇博客记录小黑第八次参加leetcode周赛(299场次)的情况,以及对题目的总结,以便鞭策自己不断前进 。

这一次AC三道题,是参加周赛以来第一次AC三道题,虽然第三道题提交的时候正好12:00,没有算到成绩中,但也是自己独立思考完成的,还是值得记录的!!!

在这里插入图片描述

题目一:6101. 判断矩阵是否是一个 X 矩阵

在这里插入图片描述

思路: 这道题为简单题。直接用暴力解法的思路进行解决。

1,遍历大小为 n ∗ n n*n nn矩阵,并检查矩阵的 i i i行的第 i i i个和第 n − 1 − i n-1-i n1i个元素是否不为0,如果为0,则返回false。

2,检查矩阵中除步骤1中的其他元素,如果不为0,则返回false。

解决代码:

package leetcode_week_competition.week299;

public class que1 {
    public static void main(String[] args) {
        int[][] grids ={{5,7,0},{0,3,1},{0,5,0}};
        boolean b = checkXMatrix(grids);
        System.out.println(b);
    }
    public static boolean checkXMatrix(int[][] grid) {
        int n = grid.length;
        for (int i = 0; i <n ; i++) {
            if (grid[i][i]==0||grid[i][n-1-i]==0){
                return false;
            }
            for (int j = 0; j <n ; j++) {
                if (j!=i &&j!=n-1-i){
                    if (grid[i][j]!=0){
                        return false;
                    }
                }
            }
        }
        return true;

    }
}

题目二:6100. 统计放置房子的方式数

在这里插入图片描述

思路:

注意点:1,街道一侧的房子放置不会影响另一侧的放置,因此只讨论一侧的情况就可了。

2,因为第i块地房子的放置与否与第i块地有关,因此可用动态规划的思路进行解决。

动态规划五部曲:

1,确定dp数组(dp table)以及下标的含义。

d p [ i ] [ j ] dp[i][j] dp[i][j]大小为(n)*(2), d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示第i块地不放房子的方案数, d p [ i ] [ 1 ] dp[i][1] dp[i][1]表示第i块地放房子的方案数。

2,确定递推公式。

d p [ i ] [ 0 ] dp[i][0] dp[i][0] :当第i块地不放房子时,第i-1快地可以放也可以不放。所以: d p [ i ] [ 0 ] = ( d p [ i − 1 ] [ 0 ] + d p [ i − 1 ] [ 1 ] ) % x ; dp[i][0] = (dp[i-1][0]+dp[i-1][1])\%x; dp[i][0]=(dp[i1][0]+dp[i1][1])%x;

d p [ i ] [ 1 ] dp[i][1] dp[i][1] :当第i块地放房子时,第i-1块地只能不放。所以 d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] ; dp[i][1] = dp[i-1][0]; dp[i][1]=dp[i1][0];

3,dp数组初始化

当只有一块地时,只有放与不放两种方案。因此: d p [ 0 ] [ 0 ] = 1 , d p [ 0 ] [ 1 ] = 1 ; dp[0][0] = 1,dp[0][1] = 1; dp[0][0]=1,dp[0][1]=1;

4,确定遍历顺序。

遍历顺序就是按照地的顺序进行。

5,举例推导。(见代码)

最后,一侧的房子放置方案数= d p [ n − 1 ] [ 0 ] + d p [ n − 1 ] [ 1 ] dp[n-1][0]+dp[n-1][1] dp[n1][0]+dp[n1][1],总的方案数即为一侧方案数取平方。

解决代码:

package leetcode_week_competition.week299;

public class que2 {
    public static void main(String[] args) {
        int n=1;
        int i = countHousePlacements(1000);
        System.out.println(i);

    }
    public static int countHousePlacements(int n) {
        int x= 1000000000+7;
        //表示街道一侧第i第放与不放的方式数,0表示不妨,1表示放
        long[][] dp =new long[n][2];
        dp[0][0] = 1;
        dp[0][1] = 1;
        for (int i = 1; i < n; i++) {
            dp[i][0] = (dp[i-1][0]%x+dp[i-1][1]%x)%x;
            dp[i][1] = dp[i-1][0]%x;
        }
        System.out.println(dp[n-1][0]%x+"======="+dp[n-1][1]%x);
        return (int)((((dp[n-1][0]+dp[n-1][1])%x)*((dp[n-1][0]+dp[n-1][1])%x))%x);
    }
}

题目三:5229. 拼接数组的最大分数

在这里插入图片描述

思路: 本题重点需要认真读题,理清题目需要求得的东西。

问题转化: 题目的要求就是交换两个数组中连续位置的元素,以使得任意一个数组的元素和最大。返回这个最大值。

步骤:

1,首先,数组chazi保存数组 n u m s 1 − n u m s 2 nums1-nums2 nums1nums2的差值,并求出数组 n u m s 1 nums1 nums1的元素和 s u m 1 sum1 sum1, n u m s 2 nums2 nums2的元素和 s u m 2 sum2 sum2

2,问题转化为:求数组中连续子数组的最大和最小和。

3,连续子数组的最大和表示,将 n u m s 1 nums1 nums1中这个连续子数组交换到 n u m s 2 nums2 nums2后, s u m 2 sum2 sum2最多能变大为 s u m 2 + m a x A n s sum2+maxAns sum2+maxAns

连续子数组的最小和的绝对值表示,将 n u m s 2 nums2 nums2中这个连续子数组交换到 n u m s 1 nums1 nums1后, s u m 1 sum1 sum1最多能变大为 s u m 1 − m i n A n s sum1-minAns sum1minAns
4,交换后只有两种情况,要么保证 s u m 1 sum1 sum1最大对应步骤3中连续子数组最小和;要么保证 s u m 2 sum2 sum2最大对应步骤3中连续子数组最大和。因此结果返回这两种情况中的最大值

解决代码:

package leetcode_week_competition.week299;

public class que3 {
    public static void main(String[] args) {
        int[] nums1 ={60,60,60};
        int[] nums2 ={10,90,10};
        int i = maximumsSplicedArray(nums1, nums2);
        System.out.println(i);
    }
    public static int maximumsSplicedArray(int[] nums1, int[] nums2) {
        int[] chazhi =new int[nums1.length];
        int sum1=0,sum2=0;
        for (int i = 0; i <nums1.length ; i++) {
            chazhi[i] = nums1[i]-nums2[i];
            sum1+=nums1[i];
            sum2+=nums2[i];
        }
        int pre = 0, pree=0,maxAns =chazhi[0],minAns=Integer.MAX_VALUE;
        for (int cha:chazhi
             ) {
            pre = Math.max(pre+cha,cha);
            pree=Math.min(pree+cha,cha);
            maxAns=Math.max(maxAns,pre);
            minAns=Math.min(minAns,pree);
        }
        return Math.max(sum1-minAns,sum2+maxAns);

    }
}

提交时间就差一分钟就AC三道了。

在这里插入图片描述

题目四:5254. 卖木头块

在这里插入图片描述

思路: 本题是一道困难题目。考查DFS的用法。参考大神灵茶山艾府的解题思路,详细步骤可查看[此页面](DFS 时间戳——处理树上问题的有力工具(Python/Java/C++/Go) - 从树中删除边的最小分数 - 力扣(LeetCode))。

关键点: 在 DFS 一棵树的过程中,维护一个全局的时间戳 c l o c k clock clock,每访问一个新的节点,就将 c l o c k clock clock 加一。同时,记录进入节点x 时的时间戳 i n [ x ] in[x] in[x],和离开(递归结束)这个节点时的时间戳 o u t [ x ] out[x] out[x]

时间戳的性质:

在这里插入图片描述

解决代码:

class Solution {
    List<Integer>[] g;
    int[] nums, xor, in, out;
    int clock;

    public int minimumScore(int[] nums, int[][] edges) {
        var n = nums.length;
        g = new ArrayList[n];
        for (var i = 0; i < n; i++) g[i] = new ArrayList<>();
        for (var e : edges) {
            int x = e[0], y = e[1];
            g[x].add(y);
            g[y].add(x);
        }
        this.nums = nums;
        xor = new int[n];
        in = new int[n];
        out = new int[n];
        dfs(0, -1);

        for (var e : edges)
            if (!isParent(e[0], e[1])) {
                var tmp = e[0];
                e[0] = e[1];
                e[1] = tmp; // swap,保证 e[0] 是 e[1] 的父节点
            }
        var ans = Integer.MAX_VALUE;
        for (var i = 0; i < edges.length; ++i) {
            int x1 = edges[i][0], y1 = edges[i][1];
            for (var j = 0; j < i; ++j) {
                int x2 = edges[j][0], y2 = edges[j][1];
                int x, y, z;
                if (isParent(y1, x2)) { // y1 是 x2 的祖先节点(或重合)
                    x = xor[y2];
                    y = xor[y1] ^ x;
                    z = xor[0] ^ xor[y1];
                } else if (isParent(y2, x1)) { // y2 是 x1 的祖先节点(或重合)
                    x = xor[y1];
                    y = xor[y2] ^ x;
                    z = xor[0] ^ xor[y2];
                } else { // 删除的两条边分别属于两颗不相交的子树
                    x = xor[y1];
                    y = xor[y2];
                    z = xor[0] ^ x ^ y;
                }
                ans = Math.min(ans, Math.max(Math.max(x, y), z) - Math.min(Math.min(x, y), z));
            }
        }
        return ans;
    }

    void dfs(int x, int fa) {
        in[x] = ++clock;
        xor[x] = nums[x];
        for (var y : g[x])
            if (y != fa) {
                dfs(y, x);
                xor[x] ^= xor[y];
            }
        out[x] = clock;
    }

    boolean isParent(int x, int y) {
        return in[x] <= in[y] && in[y] <= out[x];
    }
}

总结:以上就是LeetCode第299场周赛题目,这次可以认为是AC了三道题,是第一次一个半小时内做出三道题,表现很好,接下来还是要继续加油!!!争取稳三争四。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王小二_Leon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值