Leetcode 5448. Path Crossing
Leetcode 5449. Check If Array Pairs Are Divisible by k
Leetcode 5450. Number of Subsequences That Satisfy the Given Sum Condition
Leetcode 5451. Max Value of Equation
\newline
\newline
Leetcode 5448. Path Crossing
直接模拟这个过程即可,把走过的点的坐标放入一个Set内来检查当前点之前有没有走过。
class Solution {
public boolean isPathCrossing(String path) {
Set<String> set = new HashSet<>();
int i = 0;
int j = 0;
set.add("0#0");
for (char c : path.toCharArray()) {
switch(c) {
case 'N':
i++;
break;
case 'S':
i--;
break;
case 'E':
j++;
break;
case 'W':
j--;
break;
}
String key = i + "#" + j;
if (set.contains(key)) {
return true;
}
set.add(key);
}
return false;
}
}
T
i
m
e
:
O
(
N
)
Time: O(N)
Time:O(N)
S
p
a
c
e
:
O
(
N
)
Space:O(N)
Space:O(N)
\newline
\newline
Leetcode 5449. Check If Array Pairs Are Divisible by k
两个数之和能被k整除相当于两个数除k的余数加起来等于k。记这些数除以k的余数为r,那么只有 r r r 和 k − r , r = 1 , 2 , 3 , . . k − 1 k - r,\space r = 1, 2, 3, .. k - 1 k−r, r=1,2,3,..k−1能配对, r = = 0 r == 0 r==0和自身配对。不能忘记一种特殊情况是 r = = k / 2 r == k / 2 r==k/2。这时候, r r r也是和自己配对。
class Solution {
public boolean canArrange(int[] arr, int k) {
int[] cnt = new int[k];
for (int a : arr) {
cnt[(a % k + k) % k]++;
}
if ((cnt[0] & 1) != 0) {
return false;
}
int i = 1;
int j = k - 1;
while (i < j) {
if (cnt[i++] != cnt[j--]) {
return false;
}
}
if ((k & 1) == 0) {
if ((cnt[k >> 1] & 1) != 0) {
return false;
}
}
return true;
}
}
T
i
m
e
:
O
(
N
)
Time: O(N)
Time:O(N)
S
p
a
c
e
:
O
(
K
)
Space:O(K)
Space:O(K)
\newline
\newline
Leetcode 5450. Number of Subsequences That Satisfy the Given Sum Condition
这一题是本周赛里耗时最多的,因为一开始的思考方向不对。子序列这个说法很具有迷惑性,让我首先去往动态规划和滑动窗口方向去思考,但是收效不佳。而且因为是子序列,要保证相对顺序,所以我没有往排序的方向思考。但是后来我恍然想到,这个问题只是求子序列个数,并没有使用任何子序列的顺序性质,这和求子集的个数完全等价。如果题目换成求子集的个数,那么我会立即想到排序。
排序之后,可以使用双指针从头尾遍历数组,
- 如果当前 n u m s [ i ] + n u m s [ j ] > t a r g e t nums[i] + nums[j] > target nums[i]+nums[j]>target,那么显然 n u m s [ j ] nums[j] nums[j] 太大了, j j j应该往前移动。
- 如果和小于等于
t
a
r
g
e
t
target
target,那么从
i
i
i 到
j
j
j 之间的所有子集都是符合要求。为了不重复计算而且保证子集不为空,我们规定
n
u
m
s
[
i
]
nums[i]
nums[i]
必须取,也就是 2 j − i 2^{j - i}_{} 2j−i个子集,然后 i i i 往后移动。
class Solution {
private static final int MOD = 1000000007;
public int numSubseq(int[] nums, int target) {
int ans = 0;
Arrays.sort(nums);
int[] twoExpo = new int[nums.length];
twoExpo[0] = 1;
for (int i = 1; i < nums.length; ++i) {
twoExpo[i] = (twoExpo[i - 1] << 1) % MOD;
}
int i = 0;
int j = nums.length - 1;
while (i <= j) {
if (nums[i] + nums[j] > target) {
j--;
} else {
ans = (ans + twoExpo[j - i]) % MOD;
i++;
}
}
return ans;
}
}
T
i
m
e
:
O
(
N
L
o
g
N
)
Time: O(NLogN)
Time:O(NLogN)
S
p
a
c
e
:
O
(
N
)
Space:O(N)
Space:O(N)
\newline
\newline
Leetcode 5451. Max Value of Equation
本周的最后一题要比上一题简单很多,思路很明确。
等式
y
i
+
y
j
+
∣
x
i
−
x
j
∣
y^{}_{i} + y^{}_{j} + |x^{}_{i} - x^{}_{j}|
yi+yj+∣xi−xj∣ 相当于
x
j
+
y
j
+
y
i
−
x
i
x^{}_{j} + y^{}_{j} + y^{}_{i} - x^{}_{i}
xj+yj+yi−xi,如果
j
>
i
j > i
j>i,即
x
j
>
x
i
x^{}_{j} > x^{}_{i}
xj>xi。
如果从前往后遍历,对于当前的点 ( x j , y j ) (x^{}_{j},\space y^{}_{j}) (xj, yj),相当于我们要找到最大的 y i − x i y^{}_{i} - x^{}_{i} yi−xi。这个只需要维护一个单调递减的队列就行。我们需要在这个队列的头和尾操作。
class Solution {
private class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public int findMaxValueOfEquation(int[][] points, int k) {
LinkedList<Point> q = new LinkedList<>();
int ans = Integer.MIN_VALUE;
for (int i = 0; i < points.length; ++i) {
Point p = new Point(points[i][0], points[i][1]);
while (!q.isEmpty() && p.x - q.peekFirst().x > k) {
q.pollFirst();
}
if (!q.isEmpty()) {
ans = Math.max(ans, p.x + p.y + getVal(q.peekFirst()));
}
while (!q.isEmpty() && getVal(q.peekLast()) < getVal(p)) {
q.pollLast();
}
q.addLast(p);
}
return ans;
}
private int getVal(Point p) {
return p.y - p.x;
}
}
T
i
m
e
:
O
(
N
)
Time: O(N)
Time:O(N)
S
p
a
c
e
:
O
(
N
)
Space:O(N)
Space:O(N)
\newline
\newline