mirror of
https://github.com/CyC2018/Interview-Notebook.git
synced 2026-10-27 05:23:46 +00:00
@@ -7,6 +7,7 @@
|
||||
* [4. 第一个错误的版本](#4-第一个错误的版本)
|
||||
* [5. 旋转数组的最小数字](#5-旋转数组的最小数字)
|
||||
* [6. 查找区间](#6-查找区间)
|
||||
* [7. 两个有序数组的中位数](#7-两个有序数组的中位数)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
@@ -314,3 +315,42 @@ nums = [2,2], target = 2
|
||||
```
|
||||
|
||||
如果 h 的取值为 nums.length - 1,那么 last = findFirst(nums, target + 1) - 1 = 1 - 1 = 0。这是因为 findFirst 只会返回 [0, nums.length - 1] 范围的值,对于 findFirst([2,2], 3) ,我们希望返回 3 应该插入 nums 中的位置,也就是数组最后一个位置再往后一个位置,即 nums.length。所以我们需要将 h 取值为 nums.length,从而使得 findFirst 返回的区间更大,能够覆盖 target 大于 nums 最后一个元素的情况。
|
||||
|
||||
## 7. 两个有序数组的中位数
|
||||
|
||||
4\. Median of Two Sorted Arrays (Hard)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/median-of-two-sorted-arrays/) / [力扣](https://leetcode.cn/problems/median-of-two-sorted-arrays/)
|
||||
|
||||
题目描述:求两个有序数组合并后的中位数,要求时间复杂度为 O(log(m + n))。
|
||||
|
||||
把问题转化为求两个数组合并后第 k 小的数。比较两个数组各自的第 k / 2 个元素,较小的那个元素以及它前面的元素都不可能是第 k 小,可以一次排除,然后在剩下的部分里寻找第 k - 排除个数 小的数。k 每轮减半,时间复杂度为 O(log(m + n))。
|
||||
|
||||
```java
|
||||
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
|
||||
int total = nums1.length + nums2.length;
|
||||
if (total % 2 == 1) {
|
||||
return kth(nums1, 0, nums2, 0, total / 2 + 1);
|
||||
}
|
||||
return (kth(nums1, 0, nums2, 0, total / 2) + kth(nums1, 0, nums2, 0, total / 2 + 1)) / 2.0;
|
||||
}
|
||||
|
||||
// nums1[i..] 和 nums2[j..] 合并后第 k 小的数,k 从 1 开始
|
||||
private int kth(int[] nums1, int i, int[] nums2, int j, int k) {
|
||||
if (i == nums1.length) {
|
||||
return nums2[j + k - 1];
|
||||
}
|
||||
if (j == nums2.length) {
|
||||
return nums1[i + k - 1];
|
||||
}
|
||||
if (k == 1) {
|
||||
return Math.min(nums1[i], nums2[j]);
|
||||
}
|
||||
int a = Math.min(i + k / 2, nums1.length) - 1;
|
||||
int b = Math.min(j + k / 2, nums2.length) - 1;
|
||||
if (nums1[a] <= nums2[b]) {
|
||||
return kth(nums1, a + 1, nums2, j, k - (a - i + 1));
|
||||
}
|
||||
return kth(nums1, i, nums2, b + 1, k - (b - j + 1));
|
||||
}
|
||||
```
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
* [矩阵路径](#矩阵路径)
|
||||
* [1. 矩阵的最小路径和](#1-矩阵的最小路径和)
|
||||
* [2. 矩阵的总路径数](#2-矩阵的总路径数)
|
||||
* [3. 最大正方形](#3-最大正方形)
|
||||
* [数组区间](#数组区间)
|
||||
* [1. 数组区间和](#1-数组区间和)
|
||||
* [2. 数组中等差递增子区间的个数](#2-数组中等差递增子区间的个数)
|
||||
* [3. 最长有效括号](#3-最长有效括号)
|
||||
* [分割整数](#分割整数)
|
||||
* [1. 分割整数的最大乘积](#1-分割整数的最大乘积)
|
||||
* [2. 按平方数来分割整数](#2-按平方数来分割整数)
|
||||
@@ -241,6 +243,40 @@ public int uniquePaths(int m, int n) {
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 最大正方形
|
||||
|
||||
221\. Maximal Square (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/maximal-square/) / [力扣](https://leetcode.cn/problems/maximal-square/)
|
||||
|
||||
题目描述:在由 0 和 1 组成的矩阵中,找出只包含 1 的最大正方形的面积。
|
||||
|
||||
dp[i][j] 表示以 (i, j) 为右下角、只包含 1 的最大正方形的边长。它的边长受左边、上边和左上角三个方向的限制,取三者的最小值再加 1:
|
||||
|
||||
```text
|
||||
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
|
||||
|
||||
matrix: 1 1 1 dp: 1 1 1
|
||||
1 1 1 1 2 2
|
||||
1 1 1 1 2 3
|
||||
```
|
||||
|
||||
```java
|
||||
public int maximalSquare(char[][] matrix) {
|
||||
int m = matrix.length, n = matrix[0].length, side = 0;
|
||||
int[][] dp = new int[m + 1][n + 1];
|
||||
for (int i = 1; i <= m; i++) {
|
||||
for (int j = 1; j <= n; j++) {
|
||||
if (matrix[i - 1][j - 1] == '1') {
|
||||
dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
|
||||
side = Math.max(side, dp[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return side * side;
|
||||
}
|
||||
```
|
||||
|
||||
## 数组区间
|
||||
|
||||
### 1. 数组区间和
|
||||
@@ -336,6 +372,42 @@ public int numberOfArithmeticSlices(int[] A) {
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 最长有效括号
|
||||
|
||||
32\. Longest Valid Parentheses (Hard)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/longest-valid-parentheses/) / [力扣](https://leetcode.cn/problems/longest-valid-parentheses/)
|
||||
|
||||
```text
|
||||
Input: ")()())"
|
||||
Output: 4
|
||||
```
|
||||
|
||||
dp[i] 表示以 s[i] 结尾的最长有效括号的长度,只有 s[i] 为 ) 时才可能不为 0。以 s[i - 1] 结尾的有效括号长度为 dp[i - 1],跳过这一段之后的位置 j = i - dp[i - 1] - 1 如果是 (,就能和 s[i] 配对,长度为 dp[i - 1] + 2,再加上 j 前面紧挨着的有效括号长度 dp[j - 1]。
|
||||
|
||||
```text
|
||||
s : ( ) ( ( ) )
|
||||
dp : 0 2 0 0 2 6
|
||||
```
|
||||
|
||||
```java
|
||||
public int longestValidParentheses(String s) {
|
||||
int n = s.length(), ret = 0;
|
||||
int[] dp = new int[n];
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (s.charAt(i) != ')') {
|
||||
continue;
|
||||
}
|
||||
int j = i - dp[i - 1] - 1;
|
||||
if (j >= 0 && s.charAt(j) == '(') {
|
||||
dp[i] = dp[i - 1] + 2 + (j > 0 ? dp[j - 1] : 0);
|
||||
ret = Math.max(ret, dp[i]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
## 分割整数
|
||||
|
||||
### 1. 分割整数的最大乘积
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
* [5. 归并两个有序数组](#5-归并两个有序数组)
|
||||
* [6. 判断链表是否存在环](#6-判断链表是否存在环)
|
||||
* [7. 最长子序列](#7-最长子序列)
|
||||
* [8. 三数之和](#8-三数之和)
|
||||
* [9. 接雨水](#9-接雨水)
|
||||
* [10. 最小覆盖子串](#10-最小覆盖子串)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
@@ -290,3 +293,124 @@ private boolean isSubstr(String s, String target) {
|
||||
return j == target.length();
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 三数之和
|
||||
|
||||
15\. 3Sum (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/3sum/) / [力扣](https://leetcode.cn/problems/3sum/)
|
||||
|
||||
```text
|
||||
Input: nums = [-1, 0, 1, 2, -1, -4]
|
||||
Output: [[-1, -1, 2], [-1, 0, 1]]
|
||||
```
|
||||
|
||||
题目描述:找出所有和为 0 且不重复的三元组。
|
||||
|
||||
先排序,然后枚举第一个数 nums[i],在它右边用第 1 题的双指针方法寻找和为 -nums[i] 的两个数。去重的关键是跳过相同的值:i 跳过与前一个数相同的值,找到一组解之后,两个指针也跳过相同的值。时间复杂度为 O(N<sup>2</sup>)。
|
||||
|
||||
```java
|
||||
public List<List<Integer>> threeSum(int[] nums) {
|
||||
Arrays.sort(nums);
|
||||
List<List<Integer>> ret = new ArrayList<>();
|
||||
for (int i = 0; i < nums.length - 2; i++) {
|
||||
if (i > 0 && nums[i] == nums[i - 1]) {
|
||||
continue;
|
||||
}
|
||||
int l = i + 1, h = nums.length - 1;
|
||||
while (l < h) {
|
||||
int sum = nums[i] + nums[l] + nums[h];
|
||||
if (sum < 0) {
|
||||
l++;
|
||||
} else if (sum > 0) {
|
||||
h--;
|
||||
} else {
|
||||
ret.add(Arrays.asList(nums[i], nums[l], nums[h]));
|
||||
while (l < h && nums[l] == nums[l + 1]) {
|
||||
l++;
|
||||
}
|
||||
while (l < h && nums[h] == nums[h - 1]) {
|
||||
h--;
|
||||
}
|
||||
l++;
|
||||
h--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 接雨水
|
||||
|
||||
42\. Trapping Rain Water (Hard)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/trapping-rain-water/) / [力扣](https://leetcode.cn/problems/trapping-rain-water/)
|
||||
|
||||
```text
|
||||
Input: height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
|
||||
Output: 6
|
||||
```
|
||||
|
||||
位置 i 上方能存的水,取决于它左边最高的柱子和右边最高的柱子中较矮的那一个:water[i] = min(leftMax, rightMax) - height[i]。
|
||||
|
||||
用两个指针从两端向中间移动,分别维护 leftMax 和 rightMax。如果 leftMax < rightMax,左指针处的水位只由 leftMax 决定,因为右边已经有一根不低于 rightMax 的柱子,可以直接结算左指针并右移;反之结算右指针并左移。
|
||||
|
||||
<div align="center"> <img src="pics/trapping-rain-water.png" width="560px"/> </div><br>
|
||||
|
||||
```java
|
||||
public int trap(int[] height) {
|
||||
int l = 0, r = height.length - 1;
|
||||
int leftMax = 0, rightMax = 0, ret = 0;
|
||||
while (l < r) {
|
||||
leftMax = Math.max(leftMax, height[l]);
|
||||
rightMax = Math.max(rightMax, height[r]);
|
||||
if (leftMax < rightMax) {
|
||||
ret += leftMax - height[l++];
|
||||
} else {
|
||||
ret += rightMax - height[r--];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
## 10. 最小覆盖子串
|
||||
|
||||
76\. Minimum Window Substring (Hard)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/minimum-window-substring/) / [力扣](https://leetcode.cn/problems/minimum-window-substring/)
|
||||
|
||||
```text
|
||||
Input: s = "ADOBECODEBANC", t = "ABC"
|
||||
Output: "BANC"
|
||||
```
|
||||
|
||||
题目描述:找出 s 中包含 t 所有字符(包括重复字符)的最短子串。
|
||||
|
||||
使用滑动窗口。need[c] 表示窗口还缺几个字符 c,missing 表示一共还缺几个字符。右指针不断扩大窗口,直到 missing 为 0,此时窗口包含了 t 的所有字符;然后移动左指针缩小窗口,在窗口仍然满足条件时更新答案。
|
||||
|
||||
```java
|
||||
public String minWindow(String s, String t) {
|
||||
int[] need = new int[128];
|
||||
for (char c : t.toCharArray()) {
|
||||
need[c]++;
|
||||
}
|
||||
int missing = t.length(), start = 0, minLen = Integer.MAX_VALUE;
|
||||
for (int l = 0, r = 0; r < s.length(); r++) {
|
||||
if (need[s.charAt(r)]-- > 0) {
|
||||
missing--;
|
||||
}
|
||||
while (missing == 0) {
|
||||
if (r - l + 1 < minLen) {
|
||||
minLen = r - l + 1;
|
||||
start = l;
|
||||
}
|
||||
if (++need[s.charAt(l++)] > 0) {
|
||||
missing++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* [2. 判断数组是否含有重复元素](#2-判断数组是否含有重复元素)
|
||||
* [3. 最长和谐序列](#3-最长和谐序列)
|
||||
* [4. 最长连续序列](#4-最长连续序列)
|
||||
* [5. 和为 K 的子数组](#5-和为-k-的子数组)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
@@ -133,3 +134,32 @@ private int maxCount(Map<Integer, Integer> countForNum) {
|
||||
return max;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 和为 K 的子数组
|
||||
|
||||
560\. Subarray Sum Equals K (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/subarray-sum-equals-k/) / [力扣](https://leetcode.cn/problems/subarray-sum-equals-k/)
|
||||
|
||||
```text
|
||||
Input: nums = [1, 1, 1], k = 2
|
||||
Output: 2
|
||||
```
|
||||
|
||||
题目描述:统计和为 k 的连续子数组个数,数组元素可能为负数。
|
||||
|
||||
用 sum 表示从数组开头到当前位置的前缀和,以当前位置结尾、和为 k 的子数组,对应前面某个位置的前缀和为 sum - k。遍历时用哈希表记录每个前缀和出现的次数即可。数组中有负数,窗口变大时和不一定变大,因此不能用滑动窗口。
|
||||
|
||||
```java
|
||||
public int subarraySum(int[] nums, int k) {
|
||||
Map<Integer, Integer> cnt = new HashMap<>();
|
||||
cnt.put(0, 1);
|
||||
int sum = 0, ret = 0;
|
||||
for (int num : nums) {
|
||||
sum += num;
|
||||
ret += cnt.getOrDefault(sum - k, 0);
|
||||
cnt.merge(sum, 1, Integer::sum);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
* [7. 回文子字符串个数](#7-回文子字符串个数)
|
||||
* [8. 判断一个整数是否是回文数](#8-判断一个整数是否是回文数)
|
||||
* [9. 统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数](#9-统计二进制字符串中连续-1-和连续-0-数量相同的子字符串个数)
|
||||
* [10. 最长回文子串](#10-最长回文子串)
|
||||
* [11. 字符串相乘](#11-字符串相乘)
|
||||
* [12. 比较版本号](#12-比较版本号)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
@@ -237,3 +240,117 @@ public int countBinarySubstrings(String s) {
|
||||
return count;
|
||||
}
|
||||
```
|
||||
|
||||
## 10. 最长回文子串
|
||||
|
||||
5\. Longest Palindromic Substring (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/longest-palindromic-substring/) / [力扣](https://leetcode.cn/problems/longest-palindromic-substring/)
|
||||
|
||||
```text
|
||||
Input: s = "babad"
|
||||
Output: "bab"("aba" 也是正确答案)
|
||||
```
|
||||
|
||||
和第 7 题一样从中心扩展:回文串的中心可能是一个字符,也可能是两个字符之间,以每个位置为中心分别向两边扩展,记录最长的回文。时间复杂度为 O(N<sup>2</sup>),空间复杂度为 O(1)。
|
||||
|
||||
```java
|
||||
private int start = 0, maxLen = 0;
|
||||
|
||||
public String longestPalindrome(String s) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
extend(s, i, i); // 奇数长度
|
||||
extend(s, i, i + 1); // 偶数长度
|
||||
}
|
||||
return s.substring(start, start + maxLen);
|
||||
}
|
||||
|
||||
private void extend(String s, int l, int r) {
|
||||
while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) {
|
||||
l--;
|
||||
r++;
|
||||
}
|
||||
if (r - l - 1 > maxLen) {
|
||||
maxLen = r - l - 1;
|
||||
start = l + 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 11. 字符串相乘
|
||||
|
||||
43\. Multiply Strings (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/multiply-strings/) / [力扣](https://leetcode.cn/problems/multiply-strings/)
|
||||
|
||||
```text
|
||||
Input: num1 = "123", num2 = "45"
|
||||
Output: "5535"
|
||||
```
|
||||
|
||||
题目描述:以字符串形式给出两个非负整数,返回它们的乘积,不能把字符串直接转换为整数。
|
||||
|
||||
模拟竖式乘法。乘积最多有 m + n 位,用数组 digits 按从高位到低位的顺序保存。num1[i] 与 num2[j] 相乘的结果落在 digits[i + j + 1] 上,先把所有乘积累加到对应位置,最后从低位到高位统一处理进位。
|
||||
|
||||
```java
|
||||
public String multiply(String num1, String num2) {
|
||||
int m = num1.length(), n = num2.length();
|
||||
int[] digits = new int[m + n];
|
||||
for (int i = 0; i < m; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
digits[i + j + 1] += (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
|
||||
}
|
||||
}
|
||||
for (int k = m + n - 1; k > 0; k--) {
|
||||
digits[k - 1] += digits[k] / 10;
|
||||
digits[k] %= 10;
|
||||
}
|
||||
int k = 0;
|
||||
while (k < m + n - 1 && digits[k] == 0) {
|
||||
k++;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (; k < m + n; k++) {
|
||||
sb.append(digits[k]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
```
|
||||
|
||||
## 12. 比较版本号
|
||||
|
||||
165\. Compare Version Numbers (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/compare-version-numbers/) / [力扣](https://leetcode.cn/problems/compare-version-numbers/)
|
||||
|
||||
```text
|
||||
Input: version1 = "1.01", version2 = "1.001"
|
||||
Output: 0
|
||||
Input: version1 = "1.0.1", version2 = "1"
|
||||
Output: 1
|
||||
```
|
||||
|
||||
题目描述:版本号由 . 分隔的修订号组成,从左到右依次比较修订号的整数值,前导 0 忽略,缺少的修订号视为 0。
|
||||
|
||||
用两个指针分别扫描两个字符串,每次各解析出一段修订号的整数值进行比较,不需要先把字符串分割成数组。
|
||||
|
||||
```java
|
||||
public int compareVersion(String version1, String version2) {
|
||||
int i = 0, j = 0;
|
||||
while (i < version1.length() || j < version2.length()) {
|
||||
int x = 0, y = 0;
|
||||
while (i < version1.length() && version1.charAt(i) != '.') {
|
||||
x = x * 10 + version1.charAt(i++) - '0';
|
||||
}
|
||||
while (j < version2.length() && version2.charAt(j) != '.') {
|
||||
y = y * 10 + version2.charAt(j++) - '0';
|
||||
}
|
||||
if (x != y) {
|
||||
return x > y ? 1 : -1;
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
* [2. 3 的 n 次方](#2-3-的-n-次方)
|
||||
* [3. 乘积数组](#3-乘积数组)
|
||||
* [4. 找出数组中的乘积最大的三个数](#4-找出数组中的乘积最大的三个数)
|
||||
* [5. 用 Rand7() 实现 Rand10()](#5-用-rand7-实现-rand10)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
@@ -533,3 +534,24 @@ public int maximumProduct(int[] nums) {
|
||||
return Math.max(max1*max2*max3, max1*min1*min2);
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 用 Rand7() 实现 Rand10()
|
||||
|
||||
470\. Implement Rand10() Using Rand7() (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/implement-rand10-using-rand7/) / [力扣](https://leetcode.cn/problems/implement-rand10-using-rand7/)
|
||||
|
||||
题目描述:已知 rand7() 等概率返回 1 \~ 7,只用它实现等概率返回 1 \~ 10 的 rand10()。
|
||||
|
||||
把两次 rand7() 的结果看成一个两位的 7 进制数,(rand7() - 1) * 7 + rand7() 能等概率地生成 1 \~ 49。只保留 1 \~ 40,它们对 10 取余之后 0 \~ 9 各出现 4 次,仍然是等概率的;落在 41 \~ 49 时重新生成,这种方法称为拒绝采样。
|
||||
|
||||
```java
|
||||
public int rand10() {
|
||||
while (true) {
|
||||
int x = (rand7() - 1) * 7 + rand7();
|
||||
if (x <= 40) {
|
||||
return (x - 1) % 10 + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
* [10. 对角元素相等的矩阵](#10-对角元素相等的矩阵)
|
||||
* [11. 嵌套数组](#11-嵌套数组)
|
||||
* [12. 分隔数组](#12-分隔数组)
|
||||
* [13. 合并区间](#13-合并区间)
|
||||
* [14. 下一个排列](#14-下一个排列)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
@@ -452,3 +454,83 @@ public int maxChunksToSorted(int[] arr) {
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
## 13. 合并区间
|
||||
|
||||
56\. Merge Intervals (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/merge-intervals/) / [力扣](https://leetcode.cn/problems/merge-intervals/)
|
||||
|
||||
```text
|
||||
Input: [[1, 3], [2, 6], [8, 10], [15, 18]]
|
||||
Output: [[1, 6], [8, 10], [15, 18]]
|
||||
```
|
||||
|
||||
按区间的左端点排序后,能合并的区间一定是相邻的。依次检查每个区间:如果它的左端点不超过结果中最后一个区间的右端点,就把两者合并;否则作为一个新区间加入结果。
|
||||
|
||||
```java
|
||||
public int[][] merge(int[][] intervals) {
|
||||
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
|
||||
List<int[]> ret = new ArrayList<>();
|
||||
for (int[] cur : intervals) {
|
||||
if (!ret.isEmpty() && cur[0] <= ret.get(ret.size() - 1)[1]) {
|
||||
int[] last = ret.get(ret.size() - 1);
|
||||
last[1] = Math.max(last[1], cur[1]);
|
||||
} else {
|
||||
ret.add(cur);
|
||||
}
|
||||
}
|
||||
return ret.toArray(new int[ret.size()][]);
|
||||
}
|
||||
```
|
||||
|
||||
## 14. 下一个排列
|
||||
|
||||
31\. Next Permutation (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/next-permutation/) / [力扣](https://leetcode.cn/problems/next-permutation/)
|
||||
|
||||
```text
|
||||
Input: [1, 2, 3] Output: [1, 3, 2]
|
||||
Input: [3, 2, 1] Output: [1, 2, 3]
|
||||
```
|
||||
|
||||
题目描述:把数组原地重排为字典序中下一个更大的排列,如果已经是最大的排列,就重排为最小的排列。
|
||||
|
||||
要让排列变大又变得尽量少,应该修改尽量靠右的位置:
|
||||
|
||||
- 从右往左找到第一个满足 nums[i] < nums[i + 1] 的位置 i,i 右边是一段降序,已经是这一段能组成的最大排列;
|
||||
- 从右往左找到第一个大于 nums[i] 的元素 nums[j],交换两者,i 位置变大了一点;
|
||||
- 交换后 i 右边仍然是降序,把它反转为升序,使这一段尽量小。
|
||||
|
||||
```text
|
||||
1 5 8 4 7 6 5 3 1
|
||||
i j
|
||||
交换:1 5 8 5 7 6 4 3 1
|
||||
反转:1 5 8 5 1 3 4 6 7
|
||||
```
|
||||
|
||||
```java
|
||||
public void nextPermutation(int[] nums) {
|
||||
int i = nums.length - 2;
|
||||
while (i >= 0 && nums[i] >= nums[i + 1]) {
|
||||
i--;
|
||||
}
|
||||
if (i >= 0) {
|
||||
int j = nums.length - 1;
|
||||
while (nums[j] <= nums[i]) {
|
||||
j--;
|
||||
}
|
||||
swap(nums, i, j);
|
||||
}
|
||||
for (int l = i + 1, r = nums.length - 1; l < r; l++, r--) {
|
||||
swap(nums, l, r);
|
||||
}
|
||||
}
|
||||
|
||||
private void swap(int[] nums, int i, int j) {
|
||||
int t = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = t;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
* [4. 用栈实现括号匹配](#4-用栈实现括号匹配)
|
||||
* [5. 数组中元素与下一个比它大的元素之间的距离](#5-数组中元素与下一个比它大的元素之间的距离)
|
||||
* [6. 循环数组中比当前元素大的下一个元素](#6-循环数组中比当前元素大的下一个元素)
|
||||
* [7. 字符串解码](#7-字符串解码)
|
||||
* [8. 基本计算器](#8-基本计算器)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
@@ -232,3 +234,91 @@ public int[] nextGreaterElements(int[] nums) {
|
||||
return next;
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 字符串解码
|
||||
|
||||
394\. Decode String (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/decode-string/) / [力扣](https://leetcode.cn/problems/decode-string/)
|
||||
|
||||
```text
|
||||
Input: "3[a2[c]]"
|
||||
Output: "accaccacc"
|
||||
```
|
||||
|
||||
括号可以嵌套,用栈保存进入括号之前的状态:遇到 [ 时,把重复次数和当前已经得到的字符串分别压栈,然后从头开始记录括号内的字符串;遇到 ] 时弹出重复次数 k 和之前的字符串 prev,当前字符串变为 prev 加上括号内的字符串重复 k 次。
|
||||
|
||||
```java
|
||||
public String decodeString(String s) {
|
||||
Deque<Integer> counts = new ArrayDeque<>();
|
||||
Deque<StringBuilder> prevs = new ArrayDeque<>();
|
||||
StringBuilder cur = new StringBuilder();
|
||||
int k = 0;
|
||||
for (char c : s.toCharArray()) {
|
||||
if (Character.isDigit(c)) {
|
||||
k = k * 10 + c - '0';
|
||||
} else if (c == '[') {
|
||||
counts.push(k);
|
||||
prevs.push(cur);
|
||||
cur = new StringBuilder();
|
||||
k = 0;
|
||||
} else if (c == ']') {
|
||||
String inner = cur.toString();
|
||||
cur = prevs.pop();
|
||||
for (int n = counts.pop(); n > 0; n--) {
|
||||
cur.append(inner);
|
||||
}
|
||||
} else {
|
||||
cur.append(c);
|
||||
}
|
||||
}
|
||||
return cur.toString();
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 基本计算器
|
||||
|
||||
227\. Basic Calculator II (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/basic-calculator-ii/) / [力扣](https://leetcode.cn/problems/basic-calculator-ii/)
|
||||
|
||||
```text
|
||||
Input: " 3+5 / 2 "
|
||||
Output: 5
|
||||
```
|
||||
|
||||
题目描述:计算只包含非负整数、+、-、*、/ 和空格的表达式,整数除法向零截断。
|
||||
|
||||
乘除的优先级高于加减。读到一个数字之后,先不急着计算,等读到它后面的运算符时,再根据它前面的运算符处理:+ 把数字压栈,- 把相反数压栈,* 和 / 与栈顶元素计算后再放回。最后把栈中所有元素相加。
|
||||
|
||||
```java
|
||||
public int calculate(String s) {
|
||||
Deque<Integer> stack = new ArrayDeque<>();
|
||||
char op = '+';
|
||||
int num = 0;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
if (Character.isDigit(c)) {
|
||||
num = num * 10 + c - '0';
|
||||
}
|
||||
if ((!Character.isDigit(c) && c != ' ') || i == s.length() - 1) {
|
||||
if (op == '+') {
|
||||
stack.push(num);
|
||||
} else if (op == '-') {
|
||||
stack.push(-num);
|
||||
} else if (op == '*') {
|
||||
stack.push(stack.pop() * num);
|
||||
} else {
|
||||
stack.push(stack.pop() / num);
|
||||
}
|
||||
op = c;
|
||||
num = 0;
|
||||
}
|
||||
}
|
||||
int ret = 0;
|
||||
for (int x : stack) {
|
||||
ret += x;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
* [8. 回文链表](#8-回文链表)
|
||||
* [9. 分隔链表](#9-分隔链表)
|
||||
* [10. 链表元素按奇偶聚集](#10-链表元素按奇偶聚集)
|
||||
* [11. K 个一组翻转链表](#11-k-个一组翻转链表)
|
||||
* [12. 重排链表](#12-重排链表)
|
||||
* [13. 合并 K 个有序链表](#13-合并-k-个有序链表)
|
||||
* [14. 链表排序](#14-链表排序)
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
@@ -363,3 +367,170 @@ public ListNode oddEvenList(ListNode head) {
|
||||
return head;
|
||||
}
|
||||
```
|
||||
|
||||
## 11. K 个一组翻转链表
|
||||
|
||||
25\. Reverse Nodes in k-Group (Hard)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/reverse-nodes-in-k-group/) / [力扣](https://leetcode.cn/problems/reverse-nodes-in-k-group/)
|
||||
|
||||
```text
|
||||
Input: 1->2->3->4->5, k = 2
|
||||
Output: 2->1->4->3->5
|
||||
```
|
||||
|
||||
题目描述:每 k 个节点一组进行翻转,最后不足 k 个的节点保持原有顺序。
|
||||
|
||||
使用一个虚拟头节点 dummy,pre 指向下一组的前一个节点。先从 pre 向后走 k 步找到这一组的尾节点 tail,走不到说明剩余节点不足 k 个。然后把 pre.next 到 tail 这一段原地翻转,再把它接回原链表,最后 pre 移到这一组翻转后的末尾。
|
||||
|
||||
<div align="center"> <img src="pics/reverse-k-group.png" width="560px"/> </div><br>
|
||||
|
||||
```java
|
||||
public ListNode reverseKGroup(ListNode head, int k) {
|
||||
ListNode dummy = new ListNode(-1);
|
||||
dummy.next = head;
|
||||
ListNode pre = dummy;
|
||||
while (true) {
|
||||
ListNode tail = pre;
|
||||
for (int i = 0; i < k && tail != null; i++) {
|
||||
tail = tail.next;
|
||||
}
|
||||
if (tail == null) {
|
||||
break;
|
||||
}
|
||||
ListNode first = pre.next, next = tail.next;
|
||||
ListNode prev = next, cur = first;
|
||||
while (cur != next) {
|
||||
ListNode tmp = cur.next;
|
||||
cur.next = prev;
|
||||
prev = cur;
|
||||
cur = tmp;
|
||||
}
|
||||
pre.next = tail;
|
||||
pre = first;
|
||||
}
|
||||
return dummy.next;
|
||||
}
|
||||
```
|
||||
|
||||
## 12. 重排链表
|
||||
|
||||
143\. Reorder List (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/reorder-list/) / [力扣](https://leetcode.cn/problems/reorder-list/)
|
||||
|
||||
```text
|
||||
Input: 1->2->3->4->5
|
||||
Output: 1->5->2->4->3
|
||||
```
|
||||
|
||||
题目描述:把 L0→L1→…→Ln 重排为 L0→Ln→L1→Ln-1→…,只能修改节点的指针。
|
||||
|
||||
可以拆成三个已经解决过的子问题:用快慢指针找到中点并断开;把后半段反转;再把两段交替连接起来。
|
||||
|
||||
```java
|
||||
public void reorderList(ListNode head) {
|
||||
if (head == null || head.next == null) {
|
||||
return;
|
||||
}
|
||||
ListNode slow = head, fast = head;
|
||||
while (fast.next != null && fast.next.next != null) {
|
||||
slow = slow.next;
|
||||
fast = fast.next.next;
|
||||
}
|
||||
ListNode l2 = reverse(slow.next);
|
||||
slow.next = null;
|
||||
ListNode l1 = head;
|
||||
while (l2 != null) {
|
||||
ListNode n1 = l1.next, n2 = l2.next;
|
||||
l1.next = l2;
|
||||
l2.next = n1;
|
||||
l1 = n1;
|
||||
l2 = n2;
|
||||
}
|
||||
}
|
||||
|
||||
private ListNode reverse(ListNode head) {
|
||||
ListNode pre = null;
|
||||
while (head != null) {
|
||||
ListNode next = head.next;
|
||||
head.next = pre;
|
||||
pre = head;
|
||||
head = next;
|
||||
}
|
||||
return pre;
|
||||
}
|
||||
```
|
||||
|
||||
## 13. 合并 K 个有序链表
|
||||
|
||||
23\. Merge k Sorted Lists (Hard)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/merge-k-sorted-lists/) / [力扣](https://leetcode.cn/problems/merge-k-sorted-lists/)
|
||||
|
||||
用小顶堆保存每个链表当前的头节点,每次取出值最小的节点接到结果链表后面,再把它的下一个节点放入堆中。设一共有 N 个节点,每个节点进出堆一次,时间复杂度为 O(NlogK)。
|
||||
|
||||
也可以像归并排序那样两两合并,时间复杂度同样是 O(NlogK)。
|
||||
|
||||
```java
|
||||
public ListNode mergeKLists(ListNode[] lists) {
|
||||
PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> Integer.compare(a.val, b.val));
|
||||
for (ListNode node : lists) {
|
||||
if (node != null) {
|
||||
pq.add(node);
|
||||
}
|
||||
}
|
||||
ListNode dummy = new ListNode(-1), tail = dummy;
|
||||
while (!pq.isEmpty()) {
|
||||
ListNode node = pq.poll();
|
||||
tail.next = node;
|
||||
tail = node;
|
||||
if (node.next != null) {
|
||||
pq.add(node.next);
|
||||
}
|
||||
}
|
||||
return dummy.next;
|
||||
}
|
||||
```
|
||||
|
||||
## 14. 链表排序
|
||||
|
||||
148\. Sort List (Medium)
|
||||
|
||||
[Leetcode](https://leetcode.com/problems/sort-list/) / [力扣](https://leetcode.cn/problems/sort-list/)
|
||||
|
||||
题目描述:在 O(NlogN) 时间复杂度内对链表进行排序。
|
||||
|
||||
链表不能随机访问,适合用归并排序:用快慢指针找到中点断开,两半分别排序后,用第 3 题的方法归并。递归需要 O(logN) 的栈空间。
|
||||
|
||||
```java
|
||||
public ListNode sortList(ListNode head) {
|
||||
if (head == null || head.next == null) {
|
||||
return head;
|
||||
}
|
||||
ListNode slow = head, fast = head.next;
|
||||
while (fast != null && fast.next != null) {
|
||||
slow = slow.next;
|
||||
fast = fast.next.next;
|
||||
}
|
||||
ListNode right = slow.next;
|
||||
slow.next = null;
|
||||
return merge(sortList(head), sortList(right));
|
||||
}
|
||||
|
||||
private ListNode merge(ListNode l1, ListNode l2) {
|
||||
ListNode dummy = new ListNode(-1), tail = dummy;
|
||||
while (l1 != null && l2 != null) {
|
||||
if (l1.val <= l2.val) {
|
||||
tail.next = l1;
|
||||
l1 = l1.next;
|
||||
} else {
|
||||
tail.next = l2;
|
||||
l2 = l2.next;
|
||||
}
|
||||
tail = tail.next;
|
||||
}
|
||||
tail.next = l1 != null ? l1 : l2;
|
||||
return dummy.next;
|
||||
}
|
||||
```
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
@@ -0,0 +1,95 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="300" viewBox="0 0 600 300">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #666; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #777; text-anchor: middle; }
|
||||
.b { font-weight: bold; }
|
||||
.c { text-anchor: middle; }
|
||||
.e { text-anchor: end; }
|
||||
.note { fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.sub { font-size: 11px; fill: #888; }
|
||||
.mono { font-family: Menlo, Consolas, monospace; }
|
||||
.arrow { stroke: #666; stroke-width: 1.3; fill: none; marker-end: url(#a); }
|
||||
.red { stroke: #C0605A; marker-end: url(#r); }
|
||||
.green { stroke: #6A9F68; marker-end: url(#g); }
|
||||
.dash { stroke-dasharray: 5 4; }
|
||||
.line { stroke: #666; stroke-width: 1.3; fill: none; }
|
||||
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
|
||||
.shadow { fill: #DADADA; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#666" stroke-width="1.6"/>
|
||||
</marker>
|
||||
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#C0605A" stroke-width="1.6"/>
|
||||
</marker>
|
||||
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#6A9F68" stroke-width="1.6"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
|
||||
<text x="300" y="28" class="title">K 个一组翻转链表(k = 2)</text>
|
||||
<text x="20" y="90" class="b">翻转前</text>
|
||||
<rect x="87" y="71" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="85" y="69" width="50" height="32" rx="6" fill="#E6E6E6"/>
|
||||
<text x="110" y="89.5" class="c b">dummy</text>
|
||||
<line x1="137" y1="85" x2="163" y2="85" class="arrow "/>
|
||||
<rect x="167" y="71" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="165" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="190" y="89.5" class="c b">1</text>
|
||||
<line x1="217" y1="85" x2="243" y2="85" class="arrow "/>
|
||||
<rect x="247" y="71" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="245" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="270" y="89.5" class="c b">2</text>
|
||||
<line x1="297" y1="85" x2="323" y2="85" class="arrow "/>
|
||||
<rect x="327" y="71" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="325" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="350" y="89.5" class="c b">3</text>
|
||||
<line x1="377" y1="85" x2="403" y2="85" class="arrow "/>
|
||||
<rect x="407" y="71" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="405" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="430" y="89.5" class="c b">4</text>
|
||||
<line x1="457" y1="85" x2="483" y2="85" class="arrow "/>
|
||||
<rect x="487" y="71" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="485" y="69" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="510" y="89.5" class="c b">5</text>
|
||||
<line x1="110" y1="131" x2="110" y2="105" class="arrow "/>
|
||||
<text x="110" y="147" class="c ">pre</text>
|
||||
<line x1="190" y1="131" x2="190" y2="105" class="arrow "/>
|
||||
<text x="190" y="147" class="c ">first</text>
|
||||
<line x1="270" y1="131" x2="270" y2="105" class="arrow "/>
|
||||
<text x="270" y="147" class="c ">tail</text>
|
||||
<line x1="350" y1="131" x2="350" y2="105" class="arrow "/>
|
||||
<text x="350" y="147" class="c ">next</text>
|
||||
<text x="20" y="205" class="b">翻转后</text>
|
||||
<rect x="87" y="186" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="85" y="184" width="50" height="32" rx="6" fill="#E6E6E6"/>
|
||||
<text x="110" y="204.5" class="c b">dummy</text>
|
||||
<line x1="137" y1="200" x2="163" y2="200" class="arrow "/>
|
||||
<rect x="167" y="186" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="165" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="190" y="204.5" class="c b">2</text>
|
||||
<line x1="217" y1="200" x2="243" y2="200" class="arrow "/>
|
||||
<rect x="247" y="186" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="245" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="270" y="204.5" class="c b">1</text>
|
||||
<line x1="297" y1="200" x2="323" y2="200" class="arrow "/>
|
||||
<rect x="327" y="186" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="325" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="350" y="204.5" class="c b">3</text>
|
||||
<line x1="377" y1="200" x2="403" y2="200" class="arrow "/>
|
||||
<rect x="407" y="186" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="405" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="430" y="204.5" class="c b">4</text>
|
||||
<line x1="457" y1="200" x2="483" y2="200" class="arrow "/>
|
||||
<rect x="487" y="186" width="50" height="32" rx="6" class="shadow"/>
|
||||
<rect x="485" y="184" width="50" height="32" rx="6" fill="#B1DDF0"/>
|
||||
<text x="510" y="204.5" class="c b">5</text>
|
||||
<line x1="110" y1="246" x2="110" y2="220" class="arrow "/>
|
||||
<text x="110" y="262" class="c ">pre.next = tail</text>
|
||||
<line x1="270" y1="246" x2="270" y2="220" class="arrow green"/>
|
||||
<text x="270" y="262" class="c ok">pre = first</text>
|
||||
<text x="300" y="292" class="c sub">first 成为这一组的末尾,也是下一组的 pre</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
@@ -0,0 +1,67 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="290" viewBox="0 0 600 290">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #666; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #777; text-anchor: middle; }
|
||||
.b { font-weight: bold; }
|
||||
.c { text-anchor: middle; }
|
||||
.e { text-anchor: end; }
|
||||
.note { fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.sub { font-size: 11px; fill: #888; }
|
||||
.mono { font-family: Menlo, Consolas, monospace; }
|
||||
.arrow { stroke: #666; stroke-width: 1.3; fill: none; marker-end: url(#a); }
|
||||
.red { stroke: #C0605A; marker-end: url(#r); }
|
||||
.green { stroke: #6A9F68; marker-end: url(#g); }
|
||||
.dash { stroke-dasharray: 5 4; }
|
||||
.line { stroke: #666; stroke-width: 1.3; fill: none; }
|
||||
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
|
||||
.shadow { fill: #DADADA; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#666" stroke-width="1.6"/>
|
||||
</marker>
|
||||
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#C0605A" stroke-width="1.6"/>
|
||||
</marker>
|
||||
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#6A9F68" stroke-width="1.6"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
|
||||
<text x="300" y="28" class="title">接雨水</text>
|
||||
<text x="78" y="246" class="c sub">0</text>
|
||||
<rect x="98" y="190" width="36" height="40" fill="#9E9E9E"/>
|
||||
<text x="116" y="246" class="c sub">1</text>
|
||||
<rect x="136" y="190" width="36" height="40" fill="#D6EEF8"/>
|
||||
<text x="154" y="246" class="c sub">2</text>
|
||||
<rect x="174" y="150" width="36" height="80" fill="#9E9E9E"/>
|
||||
<text x="192" y="246" class="c sub">3</text>
|
||||
<rect x="212" y="150" width="36" height="40" fill="#D6EEF8"/>
|
||||
<rect x="212" y="190" width="36" height="40" fill="#9E9E9E"/>
|
||||
<text x="230" y="246" class="c sub">4</text>
|
||||
<rect x="250" y="150" width="36" height="80" fill="#D6EEF8"/>
|
||||
<text x="268" y="246" class="c sub">5</text>
|
||||
<rect x="288" y="150" width="36" height="40" fill="#D6EEF8"/>
|
||||
<rect x="288" y="190" width="36" height="40" fill="#9E9E9E"/>
|
||||
<text x="306" y="246" class="c sub">6</text>
|
||||
<rect x="326" y="110" width="36" height="120" fill="#9E9E9E"/>
|
||||
<text x="344" y="246" class="c sub">7</text>
|
||||
<rect x="364" y="150" width="36" height="80" fill="#9E9E9E"/>
|
||||
<text x="382" y="246" class="c sub">8</text>
|
||||
<rect x="402" y="150" width="36" height="40" fill="#D6EEF8"/>
|
||||
<rect x="402" y="190" width="36" height="40" fill="#9E9E9E"/>
|
||||
<text x="420" y="246" class="c sub">9</text>
|
||||
<rect x="440" y="150" width="36" height="80" fill="#9E9E9E"/>
|
||||
<text x="458" y="246" class="c sub">10</text>
|
||||
<rect x="478" y="190" width="36" height="40" fill="#9E9E9E"/>
|
||||
<text x="496" y="246" class="c sub">11</text>
|
||||
<line x1="54" y1="230" x2="516" y2="230" class="line"/>
|
||||
<line x1="174" y1="150" x2="364" y2="150" class="line dash"/>
|
||||
<text x="168" y="144" class="e note">leftMax = 2</text>
|
||||
<text x="368" y="124" class="note">rightMax = 3</text>
|
||||
<line x1="268" y1="86" x2="268" y2="146" class="arrow red"/>
|
||||
<text x="208" y="80" class="c">位置 5 存水 min(2, 3) - 0 = 2</text>
|
||||
<text x="300" y="278" class="c sub">灰色为柱子,浅蓝色为积水,总共 6</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
Reference in New Issue
Block a user