Skip to content

Commit 8e31fe6

Browse files
committed
✨feat: Add 1218
1 parent d28e18c commit 8e31fe6

File tree

5 files changed

+193
-0
lines changed

5 files changed

+193
-0
lines changed

Index/哈希表.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
| [987. 二叉树的垂序遍历](https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/solution/gong-shui-san-xie-yi-ti-shuang-jie-dfs-h-wfm3/) | 困难 | 🤩🤩🤩 |
3333
| [1074. 元素和为目标值的子矩阵数量](https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target/solution/gong-shui-san-xie-you-hua-mei-ju-de-ji-b-uttw/) | 困难 | 🤩🤩🤩 |
3434
| [1178. 猜字谜](https://leetcode-cn.com/problems/number-of-valid-words-for-each-puzzle/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-valid-words-for-each-puzzle/solution/xiang-jin-zhu-shi-xiang-jie-po-su-wei-yu-3cr2/) | 困难 | 🤩🤩🤩🤩 |
35+
| [1218. 最长定差子序列](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/solution/gong-shui-san-xie-jie-he-tan-xin-de-zhua-dj1k/) | 中等 | 🤩🤩🤩🤩🤩 |
3536
| [1418. 点菜展示表](https://leetcode-cn.com/problems/display-table-of-food-orders-in-a-restaurant/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/display-table-of-food-orders-in-a-restaurant/solution/gong-shui-san-xie-ha-xi-biao-yu-hong-hei-jmli/) | 中等 | 🤩🤩🤩 |
3637
| [1436. 旅行终点站](https://leetcode-cn.com/problems/destination-city/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/destination-city/solution/gong-shui-san-xie-jian-dan-fang-jia-mo-n-y47c/) | 简单 | 🤩🤩🤩🤩🤩 |
3738
| [1442. 形成两个异或相等数组的三元组数目](https://leetcode-cn.com/problems/count-triplets-that-can-form-two-arrays-of-equal-xor/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/count-triplets-that-can-form-two-arrays-of-equal-xor/solution/gong-shui-san-xie-xiang-jie-shi-yong-qia-7gzm/) | 中等 | 🤩🤩 |

Index/序列 DP.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
| [978. 最长湍流子数组](https://leetcode-cn.com/problems/longest-turbulent-subarray/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-turbulent-subarray/solution/xiang-jie-dong-tai-gui-hua-ru-he-cai-dp-3spgj/) | 中等 | 🤩🤩🤩 |
1010
| [1035. 不相交的线](https://leetcode-cn.com/problems/uncrossed-lines/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/uncrossed-lines/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-bkaas/) | 中等 | 🤩🤩🤩🤩 |
1111
| [1143. 最长公共子序列](https://leetcode-cn.com/problems/longest-common-subsequence/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-common-subsequence/solution/gong-shui-san-xie-zui-chang-gong-gong-zi-xq0h/) | 中等 | 🤩🤩🤩🤩 |
12+
| [1218. 最长定差子序列](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/solution/gong-shui-san-xie-jie-he-tan-xin-de-zhua-dj1k/) | 中等 | 🤩🤩🤩🤩🤩 |
1213
| [1473. 粉刷房子 III](https://leetcode-cn.com/problems/paint-house-iii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/paint-house-iii/solution/gong-shui-san-xie-san-wei-dong-tai-gui-h-ud7m/) | 困难 | 🤩🤩🤩🤩 |
1314
| [1713. 得到子序列的最少操作次数](https://leetcode-cn.com/problems/minimum-operations-to-make-a-subsequence/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/minimum-operations-to-make-a-subsequence/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-oj7yu/) | 困难 | 🤩🤩🤩🤩🤩 |
1415

Index/状态机 DP.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
| 题目 | 题解 | 难度 | 推荐指数 |
22
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- |
33
| [552. 学生出勤记录 II](https://leetcode-cn.com/problems/student-attendance-record-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/student-attendance-record-ii/solution/gong-shui-san-xie-yi-ti-san-jie-ji-yi-hu-fdfx/) | 困难 | 🤩🤩🤩🤩 |
4+
| [1218. 最长定差子序列](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/solution/gong-shui-san-xie-jie-he-tan-xin-de-zhua-dj1k/) | 中等 | 🤩🤩🤩🤩🤩 |
45

Index/贪心算法.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
| [781. 森林中的兔子](https://leetcode-cn.com/problems/rabbits-in-forest/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/rabbits-in-forest/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-v17p5/) | 中等 | 🤩🤩🤩🤩 |
1313
| [881. 救生艇](https://leetcode-cn.com/problems/boats-to-save-people/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/boats-to-save-people/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-hosg8/) | 中等 | 🤩🤩🤩🤩 |
1414
| [995. K 连续位的最小翻转次数](https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/solution/po-su-tan-xin-jie-fa-yu-tan-xin-chai-fen-4lyy/) | 困难 | 🤩🤩🤩 |
15+
| [1218. 最长定差子序列](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/solution/gong-shui-san-xie-jie-he-tan-xin-de-zhua-dj1k/) | 中等 | 🤩🤩🤩🤩🤩 |
1516
| [1221. 分割平衡字符串](https://leetcode-cn.com/problems/split-a-string-in-balanced-strings/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/split-a-string-in-balanced-strings/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-wumnk/) | 简单 | 🤩🤩🤩🤩 |
1617
| [1707. 与数组中元素的最大异或值](https://leetcode-cn.com/problems/maximum-xor-with-an-element-from-array/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-xor-with-an-element-from-array/solution/gong-shui-san-xie-jie-zhe-ge-wen-ti-lai-lypqr/) | 困难 | 🤩🤩🤩 |
1718
| [1713. 得到子序列的最少操作次数](https://leetcode-cn.com/problems/minimum-operations-to-make-a-subsequence/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/minimum-operations-to-make-a-subsequence/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-oj7yu/) | 困难 | 🤩🤩🤩🤩🤩 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[1218. 最长定差子序列](https://leetcode-cn.com/problems/longest-arithmetic-subsequence-of-given-difference/solution/gong-shui-san-xie-jie-he-tan-xin-de-zhua-dj1k/)** ,难度为 **中等**
4+
5+
Tag : 「贪心」、「序列 DP」、「状态机 DP」、「哈希表」
6+
7+
8+
9+
10+
给你一个整数数组 `arr` 和一个整数 `difference`,请你找出并返回 `arr` 中最长等差子序列的长度,该子序列中相邻元素之间的差等于 `difference`
11+
12+
子序列 是指在不改变其余元素顺序的情况下,通过删除一些元素或不删除任何元素而从 `arr` 派生出来的序列。
13+
14+
示例 1:
15+
```
16+
输入:arr = [1,2,3,4], difference = 1
17+
18+
输出:4
19+
20+
解释:最长的等差子序列是 [1,2,3,4]。
21+
```
22+
示例 2:
23+
```
24+
输入:arr = [1,3,5,7], difference = 1
25+
26+
输出:1
27+
28+
解释:最长的等差子序列是任意单个元素。
29+
```
30+
示例 3:
31+
```
32+
输入:arr = [1,5,7,8,5,3,4,2,1], difference = -2
33+
34+
输出:4
35+
36+
解释:最长的等差子序列是 [7,5,3,1]。
37+
```
38+
39+
提示:
40+
* $1 <= arr.length <= 10^5$
41+
* $-10^4 <= arr[i], difference <= 10^4$
42+
43+
---
44+
45+
### 状态机序列 DP + 哈希表
46+
47+
**定义 $f[i][j]$($j$ 非 $0$ 即 $1$) 为代表考虑前 $i$ 个数,且第 $i$ 个数的选择情况为 $j$ 时,得到的最长定差子序列长度。**
48+
49+
最终答案为 $\max(f[n - 1][0], f[n - 1][1])$,同时我们有显然的初始化条件 $f[0][0] = 0$ 和 $f[0][1] = 1$。
50+
51+
不失一般性考虑 $f[i][j]$ 如何转移:
52+
53+
* $f[i][0]$:明确了第 $i$ 个不选,那么此时最大长度为前一个位置的结果。即有:
54+
55+
$$
56+
f[i][0] = \max(f[i - 1][0], f[i - 1][1])
57+
$$
58+
59+
* $f[i][1]$:明确了第 $i$ 个要选,此时进行分情况讨论:
60+
61+
* $arr[i]$ 独立成为一个子序列,此时有:$f[i][1] = 1$;
62+
* $arr[i]$ 接在某一个数的后面,由于给定了差值 $difference$,可直接算得上一位的值为 $prev = arr[i] - difference$,此时应当找到值为 $prev$,下标最大(下标小于 $i$)的位置,然后从该位置转移过来,即有:$f[i][1] = f[hash[prev]][1] + 1$;
63+
64+
> 容易证明:如果存在多个位置的值为 $prev$,从中选择一个下标最大的位置(下标小于 $i$)进行转移,结果相比于最优位置不会变差。因此我们「贪心」选择下标最大的位置(下标小于 $i$)即可,这引导我们在转移过程中使用「哈希表」记录处理过的位置的值信息。
65+
66+
综上,我们有:
67+
68+
$$
69+
f[i][1] = \begin{cases}
70+
1 & hash[arr[i] - difference] = -1 \\
71+
f[hash[prev]][1] + 1 & hash[arr[i] - difference] \neq -1
72+
\end{cases}
73+
$$
74+
75+
![image.png](https://pic.leetcode-cn.com/1636067512-TKbAlo-image.png)
76+
77+
代码(使用数组充当哈希表的代码在 $P2$):
78+
```Java
79+
class Solution {
80+
public int longestSubsequence(int[] arr, int d) {
81+
int n = arr.length;
82+
Map<Integer, Integer> map = new HashMap<>();
83+
int[][] f = new int[n][2];
84+
f[0][1] = 1;
85+
map.put(arr[0], 0);
86+
for (int i = 1; i < n; i++) {
87+
f[i][0] = Math.max(f[i - 1][0], f[i - 1][1]);
88+
f[i][1] = 1;
89+
int prev = arr[i] - d;
90+
if (map.containsKey(prev)) f[i][1] = Math.max(f[i][1], f[map.get(prev)][1] + 1);
91+
map.put(arr[i], i);
92+
}
93+
return Math.max(f[n - 1][0], f[n - 1][1]);
94+
}
95+
}
96+
```
97+
98+
```Java
99+
class Solution {
100+
int N = 40009, M = N / 2;
101+
public int longestSubsequence(int[] arr, int d) {
102+
int n = arr.length;
103+
int[] hash = new int[N];
104+
Arrays.fill(hash, -1);
105+
int[][] f = new int[n][2];
106+
f[0][1] = 1;
107+
hash[arr[0] + M] = 0;
108+
for (int i = 1; i < n; i++) {
109+
f[i][0] = Math.max(f[i - 1][0], f[i - 1][1]);
110+
f[i][1] = 1;
111+
int prev = arr[i] - d;
112+
if (hash[prev + M] != -1) f[i][1] = Math.max(f[i][1], f[hash[prev + M]][1] + 1);
113+
hash[arr[i] + M] = i;
114+
}
115+
return Math.max(f[n - 1][0], f[n - 1][1]);
116+
}
117+
}
118+
```
119+
* 时间复杂度:令 $n$ 为数组长度,共有 $n * 2$ 个状态需要被计算,每个状态转移的复杂度为 $O(1)$。整体复杂度为 $O(n)$
120+
* 空间复杂度:$O(n)$
121+
122+
---
123+
124+
### 优化状态定义
125+
126+
不难发现,我们多定义一维状态来区分某个位置的值是否被选择,目的是为了正确转移出第 $i$ 位被选择的情况。
127+
128+
事实上,利用哈希表本身我们就能轻松做到这一点。
129+
130+
我们调整状态定义为:**$f[i]$ 为考虑前 $i$ 个数(第 $i$ 个数必选)时,得到的最长定差子序列长度。**
131+
132+
不失一般性考虑 $f[i]$ 该如何转移,分情况讨论:
133+
134+
* $arr[i]$ 独立成为一个子序列,此时有:$f[i] = 1$;
135+
* $arr[i]$ 接在某一个数的后面,由于给定了差值 $difference$,可直接算得上一位的值为 $prev = arr[i] - difference$,此时应当找到 $arr[j]$ 为 $prev$ 的最新位置(下标最大,同时满足 $j < i$)当时的转移结果,在此基础上加一即可,即有:$f[i] = hash[prev] + 1$;
136+
137+
138+
综上,我们有($hash$ 初始化为 $0$):
139+
140+
$$
141+
f[i] = hash[prev] + 1
142+
$$
143+
144+
![image.png](https://pic.leetcode-cn.com/1636067479-eJDRuM-image.png)
145+
146+
代码(使用数组充当哈希表的代码在 $P2$):
147+
```Java
148+
class Solution {
149+
public int longestSubsequence(int[] arr, int d) {
150+
int ans = 1;
151+
Map<Integer, Integer> map = new HashMap<>();
152+
for (int i : arr) {
153+
map.put(i, map.getOrDefault(i - d, 0) + 1);
154+
ans = Math.max(ans, map.get(i));
155+
}
156+
return ans;
157+
}
158+
}
159+
```
160+
161+
```Java
162+
class Solution {
163+
int N = 40009, M = N / 2;
164+
public int longestSubsequence(int[] arr, int d) {
165+
int ans = 1;
166+
int[] hash = new int[N];
167+
for (int i : arr) {
168+
hash[i + M] = hash[i - d + M] + 1;
169+
ans = Math.max(ans, hash[i + M]);
170+
}
171+
return ans;
172+
}
173+
}
174+
```
175+
* 时间复杂度:令 $n$ 为数组长度,共有 $n$ 个状态需要被计算,每个状态转移的复杂度为 $O(1)$。整体复杂度为 $O(n)$
176+
* 空间复杂度:$O(n)$
177+
178+
---
179+
180+
### 最后
181+
182+
这是我们「刷穿 LeetCode」系列文章的第 `No.1218` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
183+
184+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
185+
186+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
187+
188+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
189+

0 commit comments

Comments
 (0)