【题解】—— LeetCode一周小结37

简介: LeetCode每日一道一周小结37

🌟欢迎来到 我的博客 —— 探索技术的无限可能!

🌟博客的简介(文章目录)


【题解】—— 每日一道题目栏


上接:【题解】—— LeetCode一周小结36

9.合并零之间的节点

题目链接:2181. 合并零之间的节点

给你一个链表的头节点 head ,该链表包含由 0 分隔开的一连串整数。链表的 开端 和 末尾 的节点都满足 Node.val == 0 。

对于每两个相邻的 0 ,请你将它们之间的所有节点合并成一个节点,其值是所有已合并节点的值之和。然后将所有 0 移除,修改后的链表不应该含有任何 0 。

返回修改后链表的头节点 head 。

示例 1:

输入:head = [0,3,1,0,4,5,2,0]

输出:[4,11]

解释:

上图表示输入的链表。修改后的链表包含:

  • 标记为绿色的节点之和:3 + 1 = 4
  • 标记为红色的节点之和:4 + 5 + 2 = 11

示例 2:

输入:head = [0,1,0,3,0,2,2,0]

输出:[1,3,4]

解释:

上图表示输入的链表。修改后的链表包含:

  • 标记为绿色的节点之和:1 = 1
  • 标记为红色的节点之和:3 = 3
  • 标记为黄色的节点之和:2 + 2 = 4

提示:

列表中的节点数目在范围 [3, 2 * 105] 内

0 <= Node.val <= 1000

不 存在连续两个 Node.val == 0 的节点

链表的 开端 和 末尾 节点都满足 Node.val == 0

题解:

方法:模拟

       

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeNodes(ListNode head) {
        ListNode dummy = new ListNode();
        int s = 0;
        ListNode tail = dummy;
        for (ListNode cur = head.next; cur != null; cur = cur.next) {
            if (cur.val != 0) {
                s += cur.val;
            } else {
                tail.next = new ListNode(s);
                tail = tail.next;
                s = 0;
            }
        }
        return dummy.next;
    }
}

10.统计上升四元组

题目链接:2552. 统计上升四元组

给你一个长度为 n 下标从 0 开始的整数数组 nums ,它包含 1 到 n 的所有数字,请你返回上升四元组的数目。

如果一个四元组 (i, j, k, l) 满足以下条件,我们称它是上升的:

0 <= i < j < k < l < n 且

nums[i] < nums[k] < nums[j] < nums[l] 。

示例 1:

输入:nums = [1,3,2,4,5]

输出:2

解释:

  • 当 i = 0 ,j = 1 ,k = 2 且 l = 3 时,有 nums[i] < nums[k] < nums[j] < nums[l] 。
  • 当 i = 0 ,j = 1 ,k = 2 且 l = 4 时,有 nums[i] < nums[k] < nums[j] < nums[l] 。

没有其他的四元组,所以我们返回 2 。

示例 2:

输入:nums = [1,2,3,4]

输出:0

解释:只存在一个四元组 i = 0 ,j = 1 ,k = 2 ,l = 3 ,但是 nums[j] < nums[k] ,所以我们返回 0

提示:

4 <= nums.length <= 4000

1 <= nums[i] <= nums.length

nums 中所有数字 互不相同 ,nums 是一个排列。

题解:

方法:枚举

       

class Solution {
    public long countQuadruplets(int[] nums) {
        int n = nums.length;
        int[][] f = new int[n][n];
        int[][] g = new int[n][n];
        for (int j = 1; j < n - 2; ++j) {
            int cnt = 0;
            for (int l = j + 1; l < n; ++l) {
                if (nums[l] > nums[j]) {
                    ++cnt;
                }
            }
            for (int k = j + 1; k < n - 1; ++k) {
                if (nums[j] > nums[k]) {
                    f[j][k] = cnt;
                } else {
                    --cnt;
                }
            }
        }
        long ans = 0;
        for (int k = 2; k < n - 1; ++k) {
            int cnt = 0;
            for (int i = 0; i < k; ++i) {
                if (nums[i] < nums[k]) {
                    ++cnt;
                }
            }
            for (int j = k - 1; j > 0; --j) {
                if (nums[j] > nums[k]) {
                    g[j][k] = cnt;
                    ans += (long) f[j][k] * g[j][k];
                } else {
                    --cnt;
                }
            }
        }
        return ans;
    }
}

11.两个线段获得的最多奖品

题目链接:2555. 两个线段获得的最多奖品

在 X轴 上有一些奖品。给你一个整数数组 prizePositions ,它按照 非递减 顺序排列,其中 prizePositions[i] 是第 i 件奖品的位置。数轴上一个位置可能会有多件奖品。再给你一个整数 k 。

你可以同时选择两个端点为整数的线段。每个线段的长度都必须是 k 。你可以获得位置在任一线段上的所有奖品(包括线段的两个端点)。注意,两个线段可能会有相交。

比方说 k = 2 ,你可以选择线段 [1, 3] 和 [2, 4] ,你可以获得满足 1 <= prizePositions[i] <= 3 或者 2 <= prizePositions[i] <= 4 的所有奖品 i 。

请你返回在选择两个最优线段的前提下,可以获得的 最多 奖品数目。

示例 1:

输入:prizePositions = [1,1,2,2,3,3,5], k = 2

输出:7

解释:这个例子中,你可以选择线段 [1, 3] 和 [3, 5] ,获得 7 个奖品。

示例 2:

输入:prizePositions = [1,2,3,4], k = 0

输出:2

解释:这个例子中,一个选择是选择线段 [3, 3] 和 [4, 4] ,获得 2 个奖品。

提示:

1 <= prizePositions.length <= 105

1 <= prizePositions[i] <= 109

0 <= k <= 109

prizePositions 有序非递减。

题解:

方法:动态规划 滑动窗口

       

class Solution {
    public int maximizeWin(int[] prizePositions, int k) {
        int n = prizePositions.length;
        if (k * 2 + 1 >= prizePositions[n - 1] - prizePositions[0]) {
            return n;
        }
        int ans = 0;
        int left = 0;
        int[] mx = new int[n + 1];
        for (int right = 0; right < n; right++) {
            while (prizePositions[right] - prizePositions[left] > k) {
                left++;
            }
            ans = Math.max(ans, mx[left] + right - left + 1);
            mx[right + 1] = Math.max(mx[right], right - left + 1);
        }
        return ans;
    }
}

12.求出最多标记下标

题目链接:2576. 求出最多标记下标

给你一个下标从 0 开始的整数数组 nums 。

一开始,所有下标都没有被标记。你可以执行以下操作任意次:

选择两个 互不相同且未标记 的下标 i 和 j ,满足 2 * nums[i] <= nums[j] ,标记下标 i 和 j 。

请你执行上述操作任意次,返回 nums 中最多可以标记的下标数目。

示例 1:

输入:nums = [3,5,2,4]

输出:2

解释:第一次操作中,选择 i = 2 和 j = 1 ,操作可以执行的原因是 2 * nums[2] <= nums[1] ,标记下标 2

和 1 。

没有其他更多可执行的操作,所以答案为 2 。

示例 2:

输入:nums = [9,2,5,4]

输出:4

解释:第一次操作中,选择 i = 3 和 j = 0 ,操作可以执行的原因是 2 * nums[3] <= nums[0] ,标记下标 3

和 0 。

第二次操作中,选择 i = 1 和 j = 2 ,操作可以执行的原因是 2 * nums[1] <= nums[2] ,标记下标 1 和 2

没有其他更多可执行的操作,所以答案为 4 。

示例 3:

输入:nums = [7,6,8]

输出:0

解释:没有任何可以执行的操作,所以答案为 0 。

提示:

1 <= nums.length <= 105

1 <= nums[i] <= 109

题解:

方法:****

       


13.预算内的最多机器人数目

题目链接:2398. 预算内的最多机器人数目

你有 n 个机器人,给你两个下标从 0 开始的整数数组 chargeTimes 和 runningCosts ,两者长度都为 n 。第 i 个机器人充电时间为 chargeTimes[i] 单位时间,花费 runningCosts[i] 单位时间运行。再给你一个整数 budget 。

运行 k 个机器人 总开销 是 max(chargeTimes) + k * sum(runningCosts) ,其中 max(chargeTimes) 是这 k 个机器人中最大充电时间,sum(runningCosts) 是这 k 个机器人的运行时间之和。

请你返回在 不超过 budget 的前提下,你 最多 可以 连续 运行的机器人数目为多少。

示例 1:

输入:chargeTimes = [3,6,1,3,4], runningCosts = [2,1,3,4,5], budget = 25

输出:3

解释:

可以在 budget 以内运行所有单个机器人或者连续运行 2 个机器人。

选择前 3 个机器人,可以得到答案最大值 3 。总开销是 max(3,6,1) + 3 * sum(2,1,3) = 6 + 3 * 6 =

24 ,小于 25 。

可以看出无法在 budget 以内连续运行超过 3 个机器人,所以我们返回 3 。

示例 2:

输入:chargeTimes = [11,12,19], runningCosts = [10,8,7], budget = 19

输出:0

解释:即使运行任何一个单个机器人,还是会超出 budget,所以我们返回 0 。

提示:

chargeTimes.length == runningCosts.length == n

1 <= n <= 5 * 104

1 <= chargeTimes[i], runningCosts[i] <= 105

1 <= budget <= 1015

题解:

方法:滑动窗口

       

class Solution {
    public int maximumRobots(int[] chargeTimes, int[] runningCosts, long budget) {
        int ans = 0;
        int left = 0;
        long sum = 0;
        Deque<Integer> q = new ArrayDeque<>();
        for (int right = 0; right < chargeTimes.length; right++) {
            // 1. 入
            while (!q.isEmpty() && chargeTimes[right] >= chargeTimes[q.peekLast()]) {
                q.pollLast();
            }
            q.addLast(right);
            sum += runningCosts[right];
            // 2. 出
            while (!q.isEmpty() && chargeTimes[q.peekFirst()] + (right - left + 1) * sum > budget) {
                if (q.peekFirst() == left) {
                    q.pollFirst();
                }
                sum -= runningCosts[left++];
            }
            // 3. 更新答案
            ans = Math.max(ans, right - left + 1);
        }
        return ans;
    }
}

14.从字符串中移除星号

题目链接:2390. 从字符串中移除星号

给你一个包含若干星号 * 的字符串 s 。

在一步操作中,你可以:

选中 s 中的一个星号。

移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。

返回移除 所有 星号之后的字符串。

注意:

生成的输入保证总是可以执行题面中描述的操作。

可以证明结果字符串是唯一的。

示例 1:

输入:s = “leet**cod*e”

输出:“lecoe”

解释:从左到右执行移除操作:

  • 距离第 1 个星号最近的字符是 “leet**code" 中的 ‘t’ ,s 变为 "leecod*e” 。
  • 距离第 2 个星号最近的字符是 “leecode” 中的 ‘e’ ,s 变为 “lecod*e” 。
  • 距离第 3 个星号最近的字符是 “lecod*e” 中的 ‘d’ ,s 变为 “lecoe” 。

不存在其他星号,返回 “lecoe” 。

示例 2:

输入:s = “erase*****”

输出:“”

解释:整个字符串都会被移除,所以返回空字符串。

提示:

1 <= s.length <= 105

s 由小写英文字母和星号 * 组成

s 可以执行上述操作

题解:

方法:

       

class Solution {
    public String removeStars(String s) {
        StringBuilder st = new StringBuilder();
        for (char c : s.toCharArray()) {
            if (c == '*') {
                st.deleteCharAt(st.length() - 1);
            } else {
                st.append(c);
            }
        }
        return st.toString();
    }
}

15.与车相交的点

题目链接:2848. 与车相交的点

给你一个下标从 0 开始的二维整数数组 nums 表示汽车停放在数轴上的坐标。对于任意下标 i,nums[i] = [starti, endi] ,其中 starti 是第 i 辆车的起点,endi 是第 i 辆车的终点。

返回数轴上被车 任意部分 覆盖的整数点的数目。

示例 1:

输入:nums = [[3,6],[1,5],[4,7]]

输出:7

解释:从 1 到 7 的所有点都至少与一辆车相交,因此答案为 7 。

示例 2:

输入:nums = [[1,3],[5,8]]

输出:7

解释:1、2、3、5、6、7、8 共计 7 个点满足至少与一辆车相交,因此答案为 7 。

提示:

1 <= nums.length <= 100

nums[i].length == 2

1 <= starti <= endi <= 100

题解:

方法:前缀和

       

class Solution {
    public int numberOfPoints(List<List<Integer>> nums) {
        int maxEnd = 0;
        for (List<Integer> p : nums) {
            maxEnd = Math.max(maxEnd, p.get(1));
        }
        int[] diff = new int[maxEnd + 2]; // 注意下面有 end+1
        for (List<Integer> interval : nums) {
            diff[interval.get(0)]++;
            diff[interval.get(1) + 1]--;
        }
        int ans = 0;
        int s = 0;
        for (int d : diff) {
            s += d;
            if (s > 0) {
                ans++;
            }
        }
        return ans;
    }
}

下接:【题解】—— LeetCode一周小结38


相关文章
|
1月前
|
测试技术 索引
【题解】—— LeetCode一周小结40
LeetCode每日一道一周小结40
【题解】—— LeetCode一周小结41
【题解】—— LeetCode一周小结41
|
2月前
|
算法
【题解】—— LeetCode一周小结36
LeetCode每日一道一周小结36
|
3月前
|
Perl
|
3月前
|
人工智能 BI 测试技术
|
5月前
|
人工智能 BI