Skip to content

Commit ea7a105

Browse files
committed
403-982-1144-1261-1599 & 面试题05.02 (6)
1 parent bf8ccf9 commit ea7a105

File tree

13 files changed

+448
-11
lines changed

13 files changed

+448
-11
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
public class Solution403 {
2+
public boolean canCross(int[] stones) {
3+
int n = stones.length;
4+
5+
// f[i][k] 表示青蛙能否到达石子编号为 i 且上一次跳跃距离为 k
6+
boolean[][] f = new boolean[n][n];
7+
f[0][0] = true;
8+
for (int i = 1; i < n; i++) {
9+
if (stones[i] - stones[i - 1] > i) {
10+
return false;
11+
}
12+
}
13+
for (int i = 1; i < n; i++) {
14+
for (int j = i - 1; j >= 0; j--) {
15+
int k = stones[i] - stones[j];
16+
if (k > j + 1) {
17+
break;
18+
}
19+
// [k-1, k+1]
20+
f[i][k] = f[j][k - 1] || f[j][k] || f[j][k + 1];
21+
if (i == n - 1 && f[i][k]) {
22+
return true;
23+
}
24+
}
25+
}
26+
return false;
27+
}
28+
}
29+
/*
30+
403. 青蛙过河
31+
https://leetcode.cn/problems/frog-jump/
32+
33+
一只青蛙想要过河。 假定河流被等分为若干个单元格,并且在每一个单元格内都有可能放有一块石子(也有可能没有)。 青蛙可以跳上石子,但是不可以跳入水中。
34+
给你石子的位置列表 stones(用单元格序号 升序 表示), 请判定青蛙能否成功过河(即能否在最后一步跳至最后一块石子上)。开始时, 青蛙默认已站在第一块石子上,并可以假定它第一步只能跳跃 1 个单位(即只能从单元格 1 跳至单元格 2 )。
35+
如果青蛙上一步跳跃了 k 个单位,那么它接下来的跳跃距离只能选择为 k - 1、k 或 k + 1 个单位。 另请注意,青蛙只能向前方(终点的方向)跳跃。
36+
提示:
37+
2 <= stones.length <= 2000
38+
0 <= stones[i] <= 2^31 - 1
39+
stones[0] == 0
40+
stones 按严格升序排列
41+
42+
动态规划
43+
时间复杂度 O(n^2)
44+
*/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution403Tests {
5+
private final Solution403 solution403 = new Solution403();
6+
7+
@Test
8+
public void example1() {
9+
int[] stones = {0, 1, 3, 5, 6, 8, 12, 17};
10+
Assertions.assertTrue(solution403.canCross(stones));
11+
}
12+
13+
@Test
14+
public void example2() {
15+
int[] stones = {0, 1, 2, 3, 4, 8, 9, 11};
16+
Assertions.assertFalse(solution403.canCross(stones));
17+
}
18+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
public class Solution982 {
2+
public int countTriplets(int[] nums) {
3+
int[] cnt = new int[1 << 16];
4+
for (int i : nums) {
5+
for (int j : nums) {
6+
cnt[i & j]++;
7+
}
8+
}
9+
10+
int res = 0;
11+
for (int k : nums) {
12+
for (int ij = 0; ij < (1 << 16); ij++) {
13+
if ((k & ij) == 0) {
14+
res += cnt[ij];
15+
}
16+
}
17+
}
18+
return res;
19+
}
20+
}
21+
/*
22+
982. 按位与为零的三元组
23+
https://leetcode.cn/problems/triples-with-bitwise-and-equal-to-zero/
24+
25+
给你一个整数数组 nums ,返回其中 按位与三元组 的数目。
26+
按位与三元组 是由下标 (i, j, k) 组成的三元组,并满足下述全部条件:
27+
- 0 <= i < nums.length
28+
- 0 <= j < nums.length
29+
- 0 <= k < nums.length
30+
- nums[i] & nums[j] & nums[k] == 0 ,其中 & 表示按位与运算符。
31+
提示:
32+
1 <= nums.length <= 1000
33+
0 <= nums[i] < 2^16
34+
35+
三层循环 O(n^3) 会 TLE。需要使用类似 两数之和 的技巧优化至 O(n^2)
36+
时间复杂度 O(n^2)
37+
*/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution982Tests {
5+
private final Solution982 solution982 = new Solution982();
6+
7+
@Test
8+
public void example1() {
9+
int[] nums = {2, 1, 3};
10+
int expected = 12;
11+
Assertions.assertEquals(expected, solution982.countTriplets(nums));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
int[] nums = {0, 0, 0};
17+
int expected = 27;
18+
Assertions.assertEquals(expected, solution982.countTriplets(nums));
19+
}
20+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
public class Solution1114 {
2+
public int movesToMakeZigzag(int[] nums) {
3+
return Math.min(f(nums, 0), f(nums, 1));
4+
}
5+
6+
private int f(int[] nums, int pos) {
7+
int n = nums.length;
8+
int res = 0;
9+
for (int i = pos; i < n; i += 2) {
10+
int max = 0;
11+
if (i - 1 >= 0) {
12+
max = Math.max(max, nums[i] - nums[i - 1] + 1);
13+
}
14+
if (i + 1 < n) {
15+
max = Math.max(max, nums[i] - nums[i + 1] + 1);
16+
}
17+
res += max;
18+
}
19+
return res;
20+
}
21+
}
22+
/*
23+
1144. 递减元素使数组呈锯齿状
24+
https://leetcode.cn/problems/decrease-elements-to-make-array-zigzag/
25+
26+
给你一个整数数组 nums,每次 操作 会从中选择一个元素并 将该元素的值减少 1。
27+
如果符合下列情况之一,则数组 A 就是 锯齿数组:
28+
- 每个偶数索引对应的元素都大于相邻的元素,即 A[0] > A[1] < A[2] > A[3] < A[4] > ...
29+
- 或者,每个奇数索引对应的元素都大于相邻的元素,即 A[0] < A[1] > A[2] < A[3] > A[4] < ...
30+
返回将数组 nums 转换为锯齿数组所需的最小操作次数。
31+
提示:
32+
1 <= nums.length <= 1000
33+
1 <= nums[i] <= 1000
34+
35+
贪心 + 分类讨论
36+
从 0 开始或从 1 开始。
37+
时间复杂度 O(n)
38+
空间复杂度 O(1)
39+
*/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution1114Tests {
5+
private final Solution1114 solution1114 = new Solution1114();
6+
7+
@Test
8+
public void example1() {
9+
int[] nums = {1, 2, 3};
10+
int expected = 2;
11+
Assertions.assertEquals(expected, solution1114.movesToMakeZigzag(nums));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
int[] nums = {9, 6, 1, 6, 2};
17+
int expected = 4;
18+
Assertions.assertEquals(expected, solution1114.movesToMakeZigzag(nums));
19+
}
20+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import java.util.HashSet;
2+
import java.util.Set;
3+
4+
public class Solution1261 {
5+
static class FindElements {
6+
private final Set<Integer> set;
7+
8+
public FindElements(TreeNode root) {
9+
set = new HashSet<>();
10+
root.val = 0;
11+
set.add(0);
12+
dfs(root);
13+
}
14+
15+
public boolean find(int target) {
16+
return set.contains(target);
17+
}
18+
19+
private void dfs(TreeNode node) {
20+
if (node.left != null) {
21+
int val = node.val * 2 + 1;
22+
node.left.val = val;
23+
set.add(val);
24+
dfs(node.left);
25+
}
26+
if (node.right != null) {
27+
int val = node.val * 2 + 2;
28+
node.right.val = val;
29+
set.add(val);
30+
dfs(node.right);
31+
}
32+
}
33+
}
34+
}
35+
/*
36+
1261. 在受污染的二叉树中查找元素
37+
https://leetcode.cn/problems/find-elements-in-a-contaminated-binary-tree/
38+
39+
给出一个满足下述规则的二叉树:
40+
1. root.val == 0
41+
2. 如果 treeNode.val == x 且 treeNode.left != null,那么 treeNode.left.val == 2 * x + 1
42+
3. 如果 treeNode.val == x 且 treeNode.right != null,那么 treeNode.right.val == 2 * x + 2
43+
现在这个二叉树受到「污染」,所有的 treeNode.val 都变成了 -1。
44+
请你先还原二叉树,然后实现 FindElements 类:
45+
- FindElements(TreeNode* root) 用受污染的二叉树初始化对象,你需要先把它还原。
46+
- bool find(int target) 判断目标值 target 是否存在于还原后的二叉树中并返回结果。
47+
提示:
48+
TreeNode.val == -1
49+
二叉树的高度不超过 20
50+
节点的总数在 [1, 10^4] 之间
51+
调用 find() 的总次数在 [1, 10^4] 之间
52+
0 <= target <= 10^6
53+
54+
先还原存放到 hashset 中,再判断
55+
时间复杂度 O(n)
56+
空间复杂度 O(n)
57+
*/
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution1261Tests {
5+
@Test
6+
public void example1() {
7+
TreeNode root = TreeNode.buildTreeNode("[-1,null,-1]");
8+
Solution1261.FindElements findElements = new Solution1261.FindElements(root);
9+
// return False
10+
Assertions.assertFalse(findElements.find(1));
11+
// return True
12+
Assertions.assertTrue(findElements.find(2));
13+
}
14+
15+
@Test
16+
public void example2() {
17+
TreeNode root = TreeNode.buildTreeNode("[-1,-1,-1,-1,-1]");
18+
Solution1261.FindElements findElements = new Solution1261.FindElements(root);
19+
// return True
20+
Assertions.assertTrue(findElements.find(1));
21+
// return True
22+
Assertions.assertTrue(findElements.find(3));
23+
// return False
24+
Assertions.assertFalse(findElements.find(5));
25+
}
26+
27+
@Test
28+
public void example3() {
29+
TreeNode root = TreeNode.buildTreeNode("[-1,null,-1,-1,null,-1]");
30+
Solution1261.FindElements findElements = new Solution1261.FindElements(root);
31+
// return True
32+
Assertions.assertTrue(findElements.find(2));
33+
// return False
34+
Assertions.assertFalse(findElements.find(3));
35+
// return False
36+
Assertions.assertFalse(findElements.find(4));
37+
// return True
38+
Assertions.assertTrue(findElements.find(5));
39+
}
40+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
public class Solution1599 {
2+
public int minOperationsMaxProfit(int[] customers, int boardingCost, int runningCost) {
3+
// 最大化利润所需执行的 最小轮转次数
4+
int res = -1;
5+
6+
// 轮转数,抵达的游客数,当前收益,最大收益
7+
int rotations = 0;
8+
int customerCnt = 0;
9+
int curProfit = 0;
10+
int maxProfit = 0;
11+
12+
for (int customer : customers) {
13+
rotations++;
14+
customerCnt += customer;
15+
// 这一轮上 k 个人
16+
int k = Math.min(4, customerCnt);
17+
customerCnt -= k;
18+
curProfit += boardingCost * k - runningCost;
19+
20+
if (maxProfit < curProfit) {
21+
maxProfit = curProfit;
22+
res = rotations;
23+
}
24+
}
25+
if (customerCnt == 0) {
26+
return res;
27+
}
28+
29+
// 如果还有剩余的游客在等摩天轮,只有当剩余的游客带来的利润为正时,才需要考虑第二阶段
30+
int once = boardingCost * 4 - runningCost;
31+
if (once <= 0) {
32+
return res;
33+
}
34+
// 剩余轮数
35+
int remainRotations = customerCnt / 4;
36+
curProfit += remainRotations * once;
37+
rotations += remainRotations;
38+
if (maxProfit < curProfit) {
39+
maxProfit = curProfit;
40+
res = rotations;
41+
}
42+
// 剩余游客
43+
int remainCustomers = customerCnt % 4;
44+
curProfit += boardingCost * remainCustomers - runningCost;
45+
if (maxProfit < curProfit) {
46+
rotations++;
47+
maxProfit = curProfit;
48+
res = rotations;
49+
}
50+
return res;
51+
}
52+
}
53+
/*
54+
1599. 经营摩天轮的最大利润
55+
https://leetcode.cn/problems/maximum-profit-of-operating-a-centennial-wheel/
56+
57+
你正在经营一座摩天轮,该摩天轮共有 4 个座舱 ,每个座舱 最多可以容纳 4 位游客 。
58+
你可以 逆时针 轮转座舱,但每次轮转都需要支付一定的运行成本 runningCost 。摩天轮每次轮转都恰好转动 1 / 4 周。
59+
给你一个长度为 n 的数组 customers , customers[i] 是在第 i 次轮转(下标从 0 开始)之前到达的新游客的数量。这也意味着你必须在新游客到来前轮转 i 次。
60+
每位游客在登上离地面最近的座舱前都会支付登舱成本 boardingCost ,一旦该座舱再次抵达地面,他们就会离开座舱结束游玩。
61+
你可以随时停下摩天轮,即便是 在服务所有游客之前 。如果你决定停止运营摩天轮,为了保证所有游客安全着陆,将免费进行所有后续轮转 。
62+
注意,如果有超过 4 位游客在等摩天轮,那么只有 4 位游客可以登上摩天轮,其余的需要等待 下一次轮转 。
63+
返回最大化利润所需执行的 最小轮转次数 。 如果不存在利润为正的方案,则返回 -1 。
64+
提示:
65+
n == customers.length
66+
1 <= n <= 10^5
67+
0 <= customers[i] <= 50
68+
1 <= boardingCost, runningCost <= 100
69+
70+
模拟
71+
*/
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution1599Tests {
5+
private final Solution1599 solution1599 = new Solution1599();
6+
7+
@Test
8+
public void example1() {
9+
int[] customers = {8, 3};
10+
int boardingCost = 5;
11+
int runningCost = 6;
12+
int expected = 3;
13+
Assertions.assertEquals(expected, solution1599.minOperationsMaxProfit(customers, boardingCost, runningCost));
14+
}
15+
16+
@Test
17+
public void example2() {
18+
int[] customers = {10, 9, 6};
19+
int boardingCost = 6;
20+
int runningCost = 4;
21+
int expected = 7;
22+
Assertions.assertEquals(expected, solution1599.minOperationsMaxProfit(customers, boardingCost, runningCost));
23+
}
24+
25+
@Test
26+
public void example3() {
27+
int[] customers = {3, 4, 0, 5, 1};
28+
int boardingCost = 1;
29+
int runningCost = 92;
30+
int expected = -1;
31+
Assertions.assertEquals(expected, solution1599.minOperationsMaxProfit(customers, boardingCost, runningCost));
32+
}
33+
}

0 commit comments

Comments
 (0)