文章目录
Leetcode 1441. 用栈操作构建数组
注意 “Push” / “Pop” 的大写即可。
class Solution {
public List<String> buildArray(int[] target, int n) {
List<String> ret = new ArrayList<>();
int i = 1;
for (int val : target) {
while (val != i) {
ret.add("Push");
ret.add("Pop");
i++;
}
ret.add("Push");
i++;
}
return ret;
}
}
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 1442. 形成两个异或相等数组的三元组数目
根据题意,
a
=
a
r
r
[
i
]
a = arr[i]
a=arr[i] ^
a
r
r
[
i
+
1
]
arr[i + 1]
arr[i+1] ^
.
.
.
...
... ^
a
r
r
[
j
−
1
]
arr[j - 1]
arr[j−1]
b
=
a
r
r
[
j
]
b = arr[j]
b=arr[j] ^
a
r
r
[
j
+
1
]
arr[j + 1]
arr[j+1] ^
.
.
.
...
... ^
a
r
r
[
k
]
arr[k]
arr[k]
那么 a a a ^ b = 0 b = 0 b=0。
所以如果我们计算数组的
X
O
R
XOR
XOR 前缀和,那么如果
s
u
m
[
i
]
=
=
s
u
m
[
k
]
sum[i] == sum[k]
sum[i]==sum[k],就有
a
r
r
[
i
+
1
]
arr[i + 1]
arr[i+1] ^
a
r
r
[
i
+
2
]
arr[i + 2]
arr[i+2] ^
.
.
.
...
... ^
a
r
r
[
k
]
=
=
0
arr[k] == 0
arr[k]==0,
那么选取
j
=
i
+
2
,
i
+
3
,
.
.
.
k
j = i + 2, i + 3, ...k
j=i+2,i+3,...k 就能获得
k
−
i
−
1
k - i - 1
k−i−1 个不同的三元组。
这个可以用一个
H
a
s
h
M
a
p
HashMap
HashMap 实现。
class Solution {
public int countTriplets(int[] arr) {
int sum = 0;
Map<Integer, List<Integer>> map = new HashMap<>() {{
put(0, new ArrayList<Integer>() {{
add(-1);
}});
}};
int ans = 0;
for (int i = 0; i < arr.length; ++i) {
sum ^= arr[i];
if (map.containsKey(sum)) {
for (int idx : map.get(sum)) {
ans += i - idx - 1;
}
}
List<Integer> list = map.computeIfAbsent(sum, k -> new ArrayList<Integer>());
list.add(i);
}
return ans;
}
}
T
i
m
e
:
O
(
n
2
)
Time: O(n^{2}_{})
Time:O(n2)
S
p
a
c
e
:
O
(
n
)
Space:O(n)
Space:O(n)
\newline
\newline
Leetcode 1443. 收集树上所有苹果的最少时间
做两次遍历,第一次计算一个节点及其所有的子孙节点是否含有苹果。
第二次 DFS 计算时间,如果一个孩子节点及其子孙有苹果就继续递归走下去。
class Solution {
private LinkedList<Integer>[] g;
private boolean[] has;
List<Boolean> hasApple;
public int minTime(int n, int[][] edges, List<Boolean> hasApple) {
g = new LinkedList[n];
for (int i = 0; i < n; ++i) {
g[i] = new LinkedList<Integer>();
}
this.hasApple = hasApple;
has = new boolean[n];
for (int[] edge : edges) {
g[edge[0]].add(edge[1]);
g[edge[1]].add(edge[0]);
}
dfs1(0, -1);
return dfs2(0, -1);
}
// Calculate whether a node or its children have apples
private void dfs1(int u, int fa) {
if (hasApple.get(u)) {
has[u] = true;
}
for (int v : g[u]) {
if (v == fa) {
continue;
}
dfs1(v, u);
has[u] |= has[v];
}
}
private int dfs2(int u, int fa) {
int ans = 0;
for (int v : g[u]) {
if (v != fa && has[v]) {
ans++;
ans += dfs2(v, u);
ans++;
}
}
return ans;
}
}
T
i
m
e
:
O
(
V
+
E
)
Time: O(V + E)
Time:O(V+E)
S
p
a
c
e
:
O
(
V
)
Space:O(V)
Space:O(V)
\newline
\newline
Leetcode 1444. 切披萨的方案数
这一题看样子是可以往动态规划方面考虑,定义一个状态
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k] 是从
(
i
,
j
)
(i, j)
(i,j) 那一格到右下角的这一块披萨,切
k
k
k 刀共有多少种切法。那么状态转移方程就是:
d
p
[
i
]
[
j
]
[
k
]
=
∑
i
<
n
i
<
m
d
p
[
n
i
]
[
j
]
[
k
−
1
]
+
∑
j
<
n
j
<
n
d
p
[
i
]
[
n
j
]
[
k
−
1
]
dp[i][j][k] = \sum_{i < ni < m} dp[ni][j][k - 1] + \sum_{j < nj < n} dp[i][nj][k - 1]
dp[i][j][k]=i<ni<m∑dp[ni][j][k−1]+j<nj<n∑dp[i][nj][k−1]
n
i
ni
ni 表示从
n
i
ni
ni 这一行上面开始横切,
n
j
nj
nj 表示从
n
j
nj
nj 这一列左边竖切。
这里需要注意,我们仍然需要保证从
(
i
,
j
)
(i, j)
(i,j) 到
(
n
i
,
j
)
(ni, j)
(ni,j) 这上半块里面至少需要有一个苹果。对于
(
i
,
j
)
(i, j)
(i,j) 到
(
i
,
n
j
)
(i, nj)
(i,nj) 这左半块也是需要有至少一个苹果。 我们可以记录一个用
s
u
m
[
i
]
[
j
]
sum[i][j]
sum[i][j] 记录
(
i
,
j
)
(i, j)
(i,j) 到
(
m
−
1
,
n
−
1
)
(m - 1, n - 1)
(m−1,n−1) 这块区域共有多少个苹果。那么最终的状态转移方程就是:
\newline
d
p
[
i
]
[
j
]
[
k
]
=
∑
i
<
n
i
<
m
,
s
u
m
[
i
]
[
j
]
>
s
u
m
[
n
i
]
[
j
]
d
p
[
n
i
]
[
j
]
[
k
−
1
]
+
∑
j
<
n
j
<
n
,
s
u
m
[
i
]
[
j
]
>
s
u
m
[
i
]
[
n
j
]
d
p
[
i
]
[
n
j
]
[
k
−
1
]
dp[i][j][k] = \sum_{i < ni < m, sum[i][j] > sum[ni][j]} dp[ni][j][k - 1] + \sum_{j < nj < n, sum[i][j] > sum[i][nj]} dp[i][nj][k - 1]
dp[i][j][k]=i<ni<m,sum[i][j]>sum[ni][j]∑dp[ni][j][k−1]+j<nj<n,sum[i][j]>sum[i][nj]∑dp[i][nj][k−1]
\newline
初始状态
d
p
[
i
]
[
j
]
[
0
]
=
s
u
m
[
i
]
[
j
]
>
0
?
1
:
0
dp[i][j][0] = sum[i][j] > 0\space?\space1 : 0
dp[i][j][0]=sum[i][j]>0 ? 1:0 当没有切的时候,如果这一块有苹果说明是一种切法。
因为第三维只和
k
−
1
k - 1
k−1 有关,所以可以简化为二维滚动数组。
\newline
\newline
class Solution {
private static final int MOD = 1000000007;
public int ways(String[] pizza, int k) {
int m = pizza.length;
int n = pizza[0].length();
int[][] prev = new int[m][n];
int[][] sum = new int[m][n];
for (int i = m - 1; i >= 0; --i) {
for (int j = n - 1; j >= 0; --j) {
int A = i < m - 1 ? sum[i + 1][j] : 0;
int B = j < n - 1 ? sum[i][j + 1] : 0;
int C = i < m - 1 && j < n - 1 ? sum[i + 1][j + 1] : 0;
sum[i][j] = pizza[i].charAt(j) == 'A' ? 1 : 0;
sum[i][j] += A + B - C;
}
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
prev[i][j] = sum[i][j] > 0 ? 1 : 0;
}
}
for (int t = 1; t < k; ++t) {
int[][] next = new int[m][n];
for (int i = m - 1; i >= 0; --i) {
for (int j = n - 1; j >= 0; --j) {
for (int ni = i + 1; ni < m; ++ni) {
if (sum[i][j] > sum[ni][j]) {
next[i][j] = (next[i][j] + prev[ni][j]) % MOD;
}
}
for (int nj = j + 1; nj < n; ++nj) {
if (sum[i][j] > sum[i][nj]) {
next[i][j] = (next[i][j] + prev[i][nj]) % MOD;
}
}
}
}
prev = next;
}
return prev[0][0];
}
}
T
i
m
e
:
O
(
k
m
n
(
m
+
n
)
)
Time: O(kmn(m + n))
Time:O(kmn(m+n))
S
p
a
c
e
:
O
(
m
n
)
Space:O(mn)
Space:O(mn)
\newline
\newline
下面是记忆化搜索的写法
class Solution {
private static final int MOD = 1000000007;
private int[][] sum;
private int[][][] f;
private int m;
private int n;
public int ways(String[] pizza, int k) {
m = pizza.length;
n = pizza[0].length();
sum = new int[m][n];
for (int i = m - 1; i >= 0; --i) {
for (int j = n - 1; j >= 0; --j) {
sum[i][j] = pizza[i].charAt(j) == 'A' ? 1 : 0;
int A = i < m - 1 ? sum[i + 1][j] : 0;
int B = j < n - 1 ? sum[i][j + 1] : 0;
int C = i < m - 1 && j < n - 1 ? sum[i + 1][j + 1] : 0;
sum[i][j] += A + B - C;
}
}
f = new int[m][n][k + 1];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
Arrays.fill(f[i][j], -1);
}
}
return helper(0, 0, k);
}
private int helper(int row, int col, int k) {
if (f[row][col][k] >= 0) {
return f[row][col][k];
}
if (sum[row][col] < k) {
return f[row][col][k] = 0;
}
if (k == 1) {
return f[row][col][k] = 1;
}
f[row][col][k] = 0;
for (int i = row + 1; i < m; ++i) {
if (sum[row][col] > sum[i][col]) {
f[row][col][k] = (f[row][col][k] + helper(i, col, k - 1)) % MOD;
}
}
for (int j = col + 1; j < n; ++j) {
if (sum[row][col] > sum[row][j]) {
f[row][col][k] = (f[row][col][k] + helper(row, j, k - 1)) % MOD;
}
}
return f[row][col][k];
}
}
T
i
m
e
:
O
(
k
m
n
(
m
+
n
)
)
Time: O(kmn(m + n))
Time:O(kmn(m+n))
S
p
a
c
e
:
O
(
m
n
k
)
Space:O(mnk)
Space:O(mnk)
\newline
\newline