• [Leetcode Weekly Contest]285


    链接:LeetCode

    [Leetcode]2210. 统计数组中峰和谷的数量

    给你一个下标从 0 开始的整数数组 nums 。如果两侧距 i 最近的不相等邻居的值均小于 nums[i] ,则下标 i 是 nums 中,某个峰的一部分。类似地,如果两侧距 i 最近的不相等邻居的值均大于 nums[i] ,则下标 i 是 nums 中某个谷的一部分。对于相邻下标 i 和 j ,如果 nums[i] == nums[j] , 则认为这两下标属于 同一个 峰或谷。

    注意,要使某个下标所做峰或谷的一部分,那么它左右两侧必须 都 存在不相等邻居。

    返回 nums 中峰和谷的数量。

    遍历即可。

    class Solution {
        public int countHillValley(int[] nums) {
            int res = 0;
            Boolean increase = null;
            int pre = nums[0];
            for(var num:nums) {
                if(num>pre) {
                    increase = true;
                    break;
                }
                else if(num<pre) {
                    increase = false;
                    break;
                }
            }
            if(increase == null) return res;
    
            for(var num:nums) {
                if(num < pre) {
                    if(increase) res += 1;
                    increase = false;
                }
                else if(num>pre) {
                    if(!increase) res += 1;
                    increase = true;
                }
                pre = num;
            }
            return res;
        }
    }
    

    [Leetcode]2211. 统计道路上的碰撞次数

    在一条无限长的公路上有 n 辆汽车正在行驶。汽车按从左到右的顺序按从 0 到 n - 1 编号,每辆车都在一个 独特的 位置。

    给你一个下标从 0 开始的字符串 directions ,长度为 n 。directions[i] 可以是 'L'、'R' 或 'S' 分别表示第 i 辆车是向 左 、向 右 或者 停留 在当前位置。每辆车移动时 速度相同 。

    碰撞次数可以按下述方式计算:

    当两辆移动方向 相反 的车相撞时,碰撞次数加 2 。
    当一辆移动的车和一辆静止的车相撞时,碰撞次数加 1 。
    碰撞发生后,涉及的车辆将无法继续移动并停留在碰撞位置。除此之外,汽车不能改变它们的状态或移动方向。

    返回在这条道路上发生的 碰撞总次数 。

    逻辑题,去掉往左右两边开的车之后,剩下的车必然会相撞。也可以通过栈模拟,来实现。

    class Solution {
        public int countCollisions(String directions) {
            int start = 0, end = directions.length()-1;
            while(start<=end) {
                if(directions.charAt(start) != 'L') break;
                start ++;
            }
            while(start<=end) {
                if(directions.charAt(end) != 'R') break;
                end --;
            }
            int count = 0;
            for(var ch:directions.toCharArray()) {
                if(ch == 'S') count ++;
            }
            return end-start+1 - count;
        }
    }
    

    [Leetcode]2212. 射箭比赛中的最大得分

    Alice 和 Bob 是一场射箭比赛中的对手。比赛规则如下:

    Alice 先射 numArrows 支箭,然后 Bob 也射 numArrows 支箭。
    分数按下述规则计算:
    箭靶有若干整数计分区域,范围从 0 到 11 (含 0 和 11)。
    箭靶上每个区域都对应一个得分 k(范围是 0 到 11),Alice 和 Bob 分别在得分 k 区域射中 ak 和 bk 支箭。如果 ak >= bk ,那么 Alice 得 k 分。如果 ak < bk ,则 Bob 得 k 分
    如果 ak == bk == 0 ,那么无人得到 k 分。
    例如,Alice 和 Bob 都向计分为 11 的区域射 2 支箭,那么 Alice 得 11 分。如果 Alice 向计分为 11 的区域射 0 支箭,但 Bob 向同一个区域射 2 支箭,那么 Bob 得 11 分。

    给你整数 numArrows 和一个长度为 12 的整数数组 aliceArrows ,该数组表示 Alice 射中 0 到 11 每个计分区域的箭数量。现在,Bob 想要尽可能 最大化 他所能获得的总分。

    返回数组 bobArrows ,该数组表示 Bob 射中 0 到 11 每个 计分区域的箭数量。且 bobArrows 的总和应当等于 numArrows 。

    如果存在多种方法都可以使 Bob 获得最大总分,返回其中 任意一种 即可。

    二进制枚举或者动态规划。 考虑到这道题numArrows可能会很大,而枚举只有\(2^{12}-1\)种可能,二进制枚举算法更优。

    class Solution {
    
        // 二进制枚举
        public int[] maximumBobPoints(int numArrows, int[] aliceArrows) {
            int maxScore = 0, maxNeed = 0;
            int plan = 0;
            int[] res = new int[12];
            for(int i=1;i<Math.pow(2, 13);++i) {
                int need = 0, score = 0;
                for(int j=0;j<12;++j) {
                    if((i & (1<<j))!=0){
                        need += aliceArrows[j]+1;
                        score += j;
                    }
                }
                if(need <= numArrows && score > maxScore) {
                    maxScore = score;
                    maxNeed = need;
                    plan = i;
                }
            }
    
            for(int i=0;i<12;++i) {
                if((plan & (1<<i))!=0) res[i] = aliceArrows[i]+1;
            }
            res[0] += numArrows - maxNeed;
            return res;
        }
    
        // 动态规划
        public int[] maximumBobPoints(int numArrows, int[] aliceArrows) {
            int[][] dp = new int[12][numArrows+1];
            int[] res = new int[12];
            for(int i=1;i<12;++i) {
                for(int num=0;num<numArrows+1;++num) {
                    if(num>aliceArrows[i]) dp[i][num] = Math.max(dp[i-1][num], dp[i-1][num-aliceArrows[i]-1]+i);
                    else dp[i][num] = dp[i-1][num];
                }
            }
    
            for(int i=11;i>=1;--i) {
                if(dp[i][numArrows] > dp[i-1][numArrows]) {
                    res[i]  = aliceArrows[i]+1;
                    numArrows -= aliceArrows[i]+1;
                }
            }
            res[0] += numArrows;
            return res;
        }
    }
    

    [Leetcode]2213. 由单个字符重复的最长子字符串

    给你一个下标从 0 开始的字符串 s 。另给你一个下标从 0 开始、长度为 k 的字符串 queryCharacters ,一个下标从 0 开始、长度也是 k 的整数 下标 数组 queryIndices ,这两个都用来描述 k 个查询。
    第 i 个查询会将 s 中位于下标 queryIndices[i] 的字符更新为 queryCharacters[i] 。
    返回一个长度为 k 的数组 lengths ,其中 lengths[i] 是在执行第 i 个查询 之后 s 中仅由 单个字符重复 组成的 最长子字符串 的 长度 。

    一道经典的线段树应用题。使用线段树求解,我们唯一需要考虑的是:在 Node 中维护些什么信息?
    对于线段树的节点信息设计,通常会包含基本的左右端点 l、r 以及查询目标值 val ,然后再考虑维护 val 还需要一些什么辅助信息。
    对于本题,我们还需要额外维护 prefix 和 suffix,分别代表「当前区间 [l, r][l,r] 内前缀相同字符连续段的最大长度」和「当前区间 [l, r][l,r] 内后缀相同字符连续段的最大长度」。

    class Solution {
        class Node {
            int l, r, prefix, suffix, val;
            Node(int _l, int _r) {
                l = _l; r = _r;
                prefix = suffix = val = 1;
            }
        }
        char[] cs;
        Node[] tr;
        void build(int u, int l, int r) {
            tr[u] = new Node(l, r);
            if (l == r) return ;
            int mid = l + r >> 1;
            build(u << 1, l, mid);
            build(u << 1 | 1, mid + 1, r);
        }
        void update(int u, int x, char c) {
            if (tr[u].l == x && tr[u].r == x) {
                cs[x - 1] = c;
                return ;
            }
            int mid = tr[u].l + tr[u].r >> 1;
            if (x <= mid) update(u << 1, x, c);
            else update(u << 1 | 1, x, c);
            pushup(u);
        }
        int query(int u, int l, int r) {
            if (l <= tr[u].l && tr[u].r <= r) return tr[u].val;
            int ans = 0;
            int mid = tr[u].l + tr[u].r >> 1;
            if (l <= mid) ans = query(u << 1, l, r);
            if (r > mid) ans = Math.max(ans, query(u << 1 | 1, l, r));
            return ans;
        }
        void pushup(int u) {
            Node left = tr[u << 1], right = tr[u << 1 | 1];
            int aLen = left.r - left.l + 1, bLen = right.r - right.l + 1;
            char ac = cs[left.r - 1], bc = cs[right.l - 1];
            tr[u].prefix = left.prefix; tr[u].suffix = right.suffix;
            tr[u].val = Math.max(left.val, right.val);
            if (ac == bc) {
                if (left.prefix == aLen) tr[u].prefix = aLen + right.prefix;
                if (right.prefix == bLen) tr[u].suffix = bLen + left.suffix;
                tr[u].val = Math.max(tr[u].val, left.suffix + right.prefix);
            }
        }
        public int[] longestRepeating(String s, String queryCharacters, int[] queryIndices) {
            cs = s.toCharArray();
            int n = cs.length, m = queryCharacters.length();
            tr = new Node[n * 4];
            build(1, 1, n);
            for (int i = 0; i < n; i++) update(1, i + 1, cs[i]);
            int[] ans = new int[m];
            for (int i = 0; i < m; i++) {
                update(1, queryIndices[i] + 1, queryCharacters.charAt(i));
                ans[i] = query(1, 1, n);
            }
            return ans;
        }
    }
    

    Leetcode

  • 相关阅读:
    VS2008开发的MFC程序,静态连接的方法
    [delphi]参数带有默认值的函数
    __cplusplus的用处
    去掉输入法上的CH和EN
    Linux下Socket的简单使用及最简化封装
    VS2008 _CRT_SECURE_NO_WARNINGS 的问题
    VC:对话框中菜单的使用(WM_INITMENUPOPUP)
    VC:CFindReplaceDialog(非模态对话框、IsWindow()、m_fr、GetFindString())
    献给初学编程者
    VC:状态栏(AfxGetMainWnd()、GetDescendantWindow()、SetPaneInfo()、SetPaneText())
  • 原文地址:https://www.cnblogs.com/hellojamest/p/16286235.html
Copyright © 2020-2023  润新知