• 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;
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    题目二: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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    题目三: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);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    提交时间就差一分钟就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];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

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

  • 相关阅读:
    Upscayl:开源AI图像放大增强工具 | AIGC实践
    AQS源码解析 8.共享模式_Semaphore信号量
    MySQL——事务和视图
    VUE搭建后台管理界面
    OkHttpsUtil
    Zebec 生态 AMA 回顾:Nautilus 以及 $ZBC 的未来
    Node.js中常用的设计模式有哪些?
    JS的基本内容
    1.4_17 Axure RP 9 for mac 高保真原型图 - 案例16 【动态面板-滚动条6】手动制作滚动条
    接口幂等性
  • 原文地址:https://blog.csdn.net/qq_44085437/article/details/125472203