feat: add solutions to lc problems: No.3319,3322 (#3639)

This commit is contained in:
Libin YANG 2024-10-14 13:07:38 +08:00 committed by GitHub
parent 6dfa077120
commit 5d8c2f9276
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 965 additions and 29 deletions

View File

@ -37,7 +37,7 @@ tags:
<pre>
<strong>Input:</strong> root = [1,2,3], targetSum = 5
<strong>Output:</strong> false
<strong>Explanation:</strong> There two root-to-leaf paths in the tree:
<strong>Explanation:</strong> There are two root-to-leaf paths in the tree:
(1 --&gt; 2): The sum is 3.
(1 --&gt; 3): The sum is 4.
There is no root-to-leaf path with sum = 5.

View File

@ -17,7 +17,7 @@ tags:
<!-- description:start -->
<p>Given an integer array <code>nums</code> of length <code>n</code> where all the integers of <code>nums</code> are in the range <code>[1, n]</code> and each integer appears <strong>once</strong> or <strong>twice</strong>, return <em>an array of all the integers that appears <strong>twice</strong></em>.</p>
<p>Given an integer array <code>nums</code> of length <code>n</code> where all the integers of <code>nums</code> are in the range <code>[1, n]</code> and each integer appears <strong>at most</strong> <strong>twice</strong>, return <em>an array of all the integers that appears <strong>twice</strong></em>.</p>
<p>You must write an algorithm that runs in <code>O(n)</code> time and uses only <em>constant</em> auxiliary space, excluding the space needed to store the output</p>

View File

@ -158,7 +158,7 @@ public:
int superEggDrop(int k, int n) {
int f[n + 1][k + 1];
memset(f, 0, sizeof(f));
function<int(int, int)> dfs = [&](int i, int j) -> int {
auto dfs = [&](auto&& dfs, int i, int j) -> int {
if (i < 1) {
return 0;
}
@ -171,17 +171,17 @@ public:
int l = 1, r = i;
while (l < r) {
int mid = (l + r + 1) >> 1;
int a = dfs(mid - 1, j - 1);
int b = dfs(i - mid, j);
int a = dfs(dfs, mid - 1, j - 1);
int b = dfs(dfs, i - mid, j);
if (a <= b) {
l = mid;
} else {
r = mid - 1;
}
}
return f[i][j] = max(dfs(l - 1, j - 1), dfs(i - l, j)) + 1;
return f[i][j] = max(dfs(dfs, l - 1, j - 1), dfs(dfs, i - l, j)) + 1;
};
return dfs(n, k);
return dfs(dfs, n, k);
}
};
```

View File

@ -141,7 +141,7 @@ public:
int superEggDrop(int k, int n) {
int f[n + 1][k + 1];
memset(f, 0, sizeof(f));
function<int(int, int)> dfs = [&](int i, int j) -> int {
auto dfs = [&](auto&& dfs, int i, int j) -> int {
if (i < 1) {
return 0;
}
@ -154,17 +154,17 @@ public:
int l = 1, r = i;
while (l < r) {
int mid = (l + r + 1) >> 1;
int a = dfs(mid - 1, j - 1);
int b = dfs(i - mid, j);
int a = dfs(dfs, mid - 1, j - 1);
int b = dfs(dfs, i - mid, j);
if (a <= b) {
l = mid;
} else {
r = mid - 1;
}
}
return f[i][j] = max(dfs(l - 1, j - 1), dfs(i - l, j)) + 1;
return f[i][j] = max(dfs(dfs, l - 1, j - 1), dfs(dfs, i - l, j)) + 1;
};
return dfs(n, k);
return dfs(dfs, n, k);
}
};
```

View File

@ -3,7 +3,7 @@ public:
int superEggDrop(int k, int n) {
int f[n + 1][k + 1];
memset(f, 0, sizeof(f));
function<int(int, int)> dfs = [&](int i, int j) -> int {
auto dfs = [&](auto&& dfs, int i, int j) -> int {
if (i < 1) {
return 0;
}
@ -16,16 +16,16 @@ public:
int l = 1, r = i;
while (l < r) {
int mid = (l + r + 1) >> 1;
int a = dfs(mid - 1, j - 1);
int b = dfs(i - mid, j);
int a = dfs(dfs, mid - 1, j - 1);
int b = dfs(dfs, i - mid, j);
if (a <= b) {
l = mid;
} else {
r = mid - 1;
}
}
return f[i][j] = max(dfs(l - 1, j - 1), dfs(i - l, j)) + 1;
return f[i][j] = max(dfs(dfs, l - 1, j - 1), dfs(dfs, i - l, j)) + 1;
};
return dfs(n, k);
return dfs(dfs, n, k);
}
};
};

View File

@ -49,7 +49,7 @@ It can be shown that no other mapping can provide a lower cost.
</pre>
<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/3000-3099/3016.Minimum%20Number%20of%20Pushes%20to%20Type%20Word%20II/images/keypadv2e2.png" style="width: 329px; height: 313px;" />
<img alt="" src="https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/3000-3099/3016.Minimum%20Number%20of%20Pushes%20to%20Type%20Word%20II/images/edited.png" style="width: 329px; height: 313px;" />
<pre>
<strong>Input:</strong> word = &quot;xyzxyzxyzxyz&quot;
<strong>Output:</strong> 12

View File

@ -37,6 +37,8 @@ tags:
<p><strong>Explanation:</strong></p>
<p>The subarray <code>[3]</code> has <code>OR</code> value of <code>3</code>. Hence, we return <code>1</code>.</p>
<p>Note that <code>[2]</code> is also a special subarray.</p>
</div>
<p><strong class="example">Example 2:</strong></p>

View File

@ -22,8 +22,6 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3314.Co
<p>If it is <em>not possible</em> to find such a value for <code>ans[i]</code> that satisfies the <strong>condition</strong>, then set <code>ans[i] = -1</code>.</p>
<p>A <strong>prime number</strong> is a natural number greater than 1 with only two factors, 1 and itself.</p>
<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

View File

@ -22,8 +22,6 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3315.Co
<p>If it is <em>not possible</em> to find such a value for <code>ans[i]</code> that satisfies the <strong>condition</strong>, then set <code>ans[i] = -1</code>.</p>
<p>A <strong>prime number</strong> is a natural number greater than 1 with only two factors, 1 and itself.</p>
<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

View File

@ -27,8 +27,6 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3316.Fi
<p>Return the <strong>maximum</strong> number of <em>operations</em> that can be performed.</p>
<p>A <strong>subsequence</strong> is a string that can be derived from another string by deleting some or no characters without changing the order of the remaining characters.</p>
<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

View File

@ -83,32 +83,213 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3319.K-
<!-- solution:start -->
### 方法一
### 方法一DFS + 排序
我们定义一个函数 $\textit{dfs}$,用于计算以当前节点为根节点的完美二叉子树的大小,用一个数组 $\textit{nums}$ 记录所有完美二叉子树的大小。如果以当前节点为根节点的子树不是完美二叉子树,则返回 $-1$。
函数 $\textit{dfs}$ 的执行过程如下:
1. 如果当前节点为空,则返回 $0$
2. 递归计算左子树和右子树的完美二叉子树的大小,分别记为 $l$ 和 $r$
3. 如果左子树和右子树的大小不相等,或者左子树和右子树的大小小于 $0$,则返回 $-1$
4. 计算当前节点的完美二叉子树的大小 $\textit{cnt} = l + r + 1$,并将 $\textit{cnt}$ 添加到数组 $\textit{nums}$ 中;
5. 返回 $\textit{cnt}$。
我们调用 $\textit{dfs}$ 函数计算出所有完美二叉子树的大小,如果数组 $\textit{nums}$ 的长度小于 $k$,则返回 $-1$,否则对数组 $\textit{nums}$ 进行降序排序,返回第 $k$ 大的完美二叉子树的大小。
时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 是二叉树的节点数。
<!-- tabs:start -->
#### Python3
```python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def kthLargestPerfectSubtree(self, root: Optional[TreeNode], k: int) -> int:
def dfs(root: Optional[TreeNode]) -> int:
if root is None:
return 0
l, r = dfs(root.left), dfs(root.right)
if l < 0 or l != r:
return -1
cnt = l + r + 1
nums.append(cnt)
return cnt
nums = []
dfs(root)
if len(nums) < k:
return -1
nums.sort(reverse=True)
return nums[k - 1]
```
#### Java
```java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private List<Integer> nums = new ArrayList<>();
public int kthLargestPerfectSubtree(TreeNode root, int k) {
dfs(root);
if (nums.size() < k) {
return -1;
}
nums.sort(Comparator.reverseOrder());
return nums.get(k - 1);
}
private int dfs(TreeNode root) {
if (root == null) {
return 0;
}
int l = dfs(root.left);
int r = dfs(root.right);
if (l < 0 || l != r) {
return -1;
}
int cnt = l + r + 1;
nums.add(cnt);
return cnt;
}
}
```
#### C++
```cpp
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int kthLargestPerfectSubtree(TreeNode* root, int k) {
vector<int> nums;
auto dfs = [&](auto&& dfs, TreeNode* root) -> int {
if (!root) {
return 0;
}
int l = dfs(dfs, root->left);
int r = dfs(dfs, root->right);
if (l < 0 || l != r) {
return -1;
}
int cnt = l + r + 1;
nums.push_back(cnt);
return cnt;
};
dfs(dfs, root);
if (nums.size() < k) {
return -1;
}
ranges::sort(nums, greater<int>());
return nums[k - 1];
}
};
```
#### Go
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func kthLargestPerfectSubtree(root *TreeNode, k int) int {
nums := []int{}
var dfs func(*TreeNode) int
dfs = func(root *TreeNode) int {
if root == nil {
return 0
}
l, r := dfs(root.Left), dfs(root.Right)
if l < 0 || l != r {
return -1
}
cnt := l + r + 1
nums = append(nums, cnt)
return cnt
}
dfs(root)
if len(nums) < k {
return -1
}
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
return nums[k-1]
}
```
#### TypeScript
```ts
/**
* Definition for a binary tree node.
* class TreeNode {
* val: number
* left: TreeNode | null
* right: TreeNode | null
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
* }
*/
function kthLargestPerfectSubtree(root: TreeNode | null, k: number): number {
const nums: number[] = [];
const dfs = (root: TreeNode | null): number => {
if (!root) {
return 0;
}
const l = dfs(root.left);
const r = dfs(root.right);
if (l < 0 || l !== r) {
return -1;
}
const cnt = l + r + 1;
nums.push(cnt);
return cnt;
};
dfs(root);
if (nums.length < k) {
return -1;
}
return nums.sort((a, b) => b - a)[k - 1];
}
```
<!-- tabs:end -->

View File

@ -79,32 +79,213 @@ The <code>2<sup>nd</sup></code> largest size is 3.</p>
<!-- solution:start -->
### Solution 1
### Solution 1: DFS + Sorting
We define a function $\textit{dfs}$ to calculate the size of the perfect binary subtree rooted at the current node, using an array $\textit{nums}$ to record the sizes of all perfect binary subtrees. If the subtree rooted at the current node is not a perfect binary subtree, it returns $-1$.
The execution process of the function $\textit{dfs}$ is as follows:
1. If the current node is null, return $0$;
2. Recursively calculate the sizes of the perfect binary subtrees of the left and right subtrees, denoted as $l$ and $r$ respectively;
3. If the sizes of the left and right subtrees are not equal, or if the sizes of the left and right subtrees are less than $0$, return $-1$;
4. Calculate the size of the perfect binary subtree rooted at the current node $\textit{cnt} = l + r + 1$, and add $\textit{cnt}$ to the array $\textit{nums}$;
5. Return $\textit{cnt}$.
We call the $\textit{dfs}$ function to calculate the sizes of all perfect binary subtrees. If the length of the array $\textit{nums}$ is less than $k$, return $-1$. Otherwise, sort the array $\textit{nums}$ in descending order and return the $k$-th largest perfect binary subtree size.
The time complexity is $O(n \times \log n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree.
<!-- tabs:start -->
#### Python3
```python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def kthLargestPerfectSubtree(self, root: Optional[TreeNode], k: int) -> int:
def dfs(root: Optional[TreeNode]) -> int:
if root is None:
return 0
l, r = dfs(root.left), dfs(root.right)
if l < 0 or l != r:
return -1
cnt = l + r + 1
nums.append(cnt)
return cnt
nums = []
dfs(root)
if len(nums) < k:
return -1
nums.sort(reverse=True)
return nums[k - 1]
```
#### Java
```java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private List<Integer> nums = new ArrayList<>();
public int kthLargestPerfectSubtree(TreeNode root, int k) {
dfs(root);
if (nums.size() < k) {
return -1;
}
nums.sort(Comparator.reverseOrder());
return nums.get(k - 1);
}
private int dfs(TreeNode root) {
if (root == null) {
return 0;
}
int l = dfs(root.left);
int r = dfs(root.right);
if (l < 0 || l != r) {
return -1;
}
int cnt = l + r + 1;
nums.add(cnt);
return cnt;
}
}
```
#### C++
```cpp
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int kthLargestPerfectSubtree(TreeNode* root, int k) {
vector<int> nums;
auto dfs = [&](auto&& dfs, TreeNode* root) -> int {
if (!root) {
return 0;
}
int l = dfs(dfs, root->left);
int r = dfs(dfs, root->right);
if (l < 0 || l != r) {
return -1;
}
int cnt = l + r + 1;
nums.push_back(cnt);
return cnt;
};
dfs(dfs, root);
if (nums.size() < k) {
return -1;
}
ranges::sort(nums, greater<int>());
return nums[k - 1];
}
};
```
#### Go
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func kthLargestPerfectSubtree(root *TreeNode, k int) int {
nums := []int{}
var dfs func(*TreeNode) int
dfs = func(root *TreeNode) int {
if root == nil {
return 0
}
l, r := dfs(root.Left), dfs(root.Right)
if l < 0 || l != r {
return -1
}
cnt := l + r + 1
nums = append(nums, cnt)
return cnt
}
dfs(root)
if len(nums) < k {
return -1
}
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
return nums[k-1]
}
```
#### TypeScript
```ts
/**
* Definition for a binary tree node.
* class TreeNode {
* val: number
* left: TreeNode | null
* right: TreeNode | null
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
* }
*/
function kthLargestPerfectSubtree(root: TreeNode | null, k: number): number {
const nums: number[] = [];
const dfs = (root: TreeNode | null): number => {
if (!root) {
return 0;
}
const l = dfs(root.left);
const r = dfs(root.right);
if (l < 0 || l !== r) {
return -1;
}
const cnt = l + r + 1;
nums.push(cnt);
return cnt;
};
dfs(root);
if (nums.length < k) {
return -1;
}
return nums.sort((a, b) => b - a)[k - 1];
}
```
<!-- tabs:end -->

View File

@ -0,0 +1,36 @@
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int kthLargestPerfectSubtree(TreeNode* root, int k) {
vector<int> nums;
auto dfs = [&](auto&& dfs, TreeNode* root) -> int {
if (!root) {
return 0;
}
int l = dfs(dfs, root->left);
int r = dfs(dfs, root->right);
if (l < 0 || l != r) {
return -1;
}
int cnt = l + r + 1;
nums.push_back(cnt);
return cnt;
};
dfs(dfs, root);
if (nums.size() < k) {
return -1;
}
ranges::sort(nums, greater<int>());
return nums[k - 1];
}
};

View File

@ -0,0 +1,30 @@
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func kthLargestPerfectSubtree(root *TreeNode, k int) int {
nums := []int{}
var dfs func(*TreeNode) int
dfs = func(root *TreeNode) int {
if root == nil {
return 0
}
l, r := dfs(root.Left), dfs(root.Right)
if l < 0 || l != r {
return -1
}
cnt := l + r + 1
nums = append(nums, cnt)
return cnt
}
dfs(root)
if len(nums) < k {
return -1
}
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
return nums[k-1]
}

View File

@ -0,0 +1,41 @@
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private List<Integer> nums = new ArrayList<>();
public int kthLargestPerfectSubtree(TreeNode root, int k) {
dfs(root);
if (nums.size() < k) {
return -1;
}
nums.sort(Comparator.reverseOrder());
return nums.get(k - 1);
}
private int dfs(TreeNode root) {
if (root == null) {
return 0;
}
int l = dfs(root.left);
int r = dfs(root.right);
if (l < 0 || l != r) {
return -1;
}
int cnt = l + r + 1;
nums.add(cnt);
return cnt;
}
}

View File

@ -0,0 +1,24 @@
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def kthLargestPerfectSubtree(self, root: Optional[TreeNode], k: int) -> int:
def dfs(root: Optional[TreeNode]) -> int:
if root is None:
return 0
l, r = dfs(root.left), dfs(root.right)
if l < 0 or l != r:
return -1
cnt = l + r + 1
nums.append(cnt)
return cnt
nums = []
dfs(root)
if len(nums) < k:
return -1
nums.sort(reverse=True)
return nums[k - 1]

View File

@ -0,0 +1,35 @@
/**
* Definition for a binary tree node.
* class TreeNode {
* val: number
* left: TreeNode | null
* right: TreeNode | null
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
* }
*/
function kthLargestPerfectSubtree(root: TreeNode | null, k: number): number {
const nums: number[] = [];
const dfs = (root: TreeNode | null): number => {
if (!root) {
return 0;
}
const l = dfs(root.left);
const r = dfs(root.right);
if (l < 0 || l !== r) {
return -1;
}
const cnt = l + r + 1;
nums.push(cnt);
return cnt;
};
dfs(root);
if (nums.length < k) {
return -1;
}
return nums.sort((a, b) => b - a)[k - 1];
}

View File

@ -0,0 +1,189 @@
---
comments: true
difficulty: 中等
edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3322.Premier%20League%20Table%20Ranking%20III/README.md
tags:
- 数据库
---
<!-- problem:start -->
# [3322. 英超积分榜排名 III 🔒](https://leetcode.cn/problems/premier-league-table-ranking-iii)
[English Version](/solution/3300-3399/3322.Premier%20League%20Table%20Ranking%20III/README_EN.md)
## 题目描述
<!-- description:start -->
<p>表:<code>SeasonStats</code></p>
<pre>
+------------------+---------+
| Column Name | Type |
+------------------+---------+
| season_id | int |
| team_id | int |
| team_name | varchar |
| matches_played | int |
| wins | int |
| draws | int |
| losses | int |
| goals_for | int |
| goals_against | int |
+------------------+---------+
(season_id, team_id) 是这张表的唯一主键。
这张表包含每个赛季中每支球队的赛季 id队伍 id队伍名比赛场次赢场平局输场进球数 (goals_for),以及失球数 (goals_against)。
</pre>
<p>编写一个解决方案来计算&nbsp;<strong>每个赛季每支球队的积分,净胜球&nbsp;</strong>&nbsp;<strong>排名</strong>。排名应确定如下:</p>
<ul>
<li>球队首先按总分排名(从高到低)</li>
<li>如果积分持平,球队就会根据净胜球(从最高到最低)进行排名</li>
<li>如果净胜球也持平,则球队将按球队名称按字母顺序排名</li>
</ul>
<p>积分如下计算:</p>
<ul>
<li><strong>赢局</strong>&nbsp;<code>3</code>&nbsp;点得分</li>
<li><strong>平局</strong>&nbsp;<code>1</code>&nbsp;点得分</li>
<li><strong>输局</strong>&nbsp;<code>0</code>&nbsp;点得分</li>
</ul>
<p>净胜球计算如下:<code>goals_for - goals_against</code></p>
<p>返回结果表以&nbsp;<code>season_id</code> <strong>升序</strong>&nbsp;排序,然后以&nbsp;<code>rank</code> <strong>升序</strong>&nbsp;排序,最后以&nbsp;<code>team_name</code> <strong>升序&nbsp;</strong>排序。</p>
<p>结果格式如下所示。</p>
<p>&nbsp;</p>
<p><strong class="example">示例:</strong></p>
<p><strong>输入:</strong></p>
<p><code>SeasonStats</code>&nbsp;表:</p>
<pre>
+------------+---------+-------------------+----------------+------+-------+--------+-----------+---------------+
| season_id | team_id | team_name | matches_played | wins | draws | losses | goals_for | goals_against |
+------------+---------+-------------------+----------------+------+-------+--------+-----------+---------------+
| 2021 | 1 | Manchester City | 38 | 29 | 6 | 3 | 99 | 26 |
| 2021 | 2 | Liverpool | 38 | 28 | 8 | 2 | 94 | 26 |
| 2021 | 3 | Chelsea | 38 | 21 | 11 | 6 | 76 | 33 |
| 2021 | 4 | Tottenham | 38 | 22 | 5 | 11 | 69 | 40 |
| 2021 | 5 | Arsenal | 38 | 22 | 3 | 13 | 61 | 48 |
| 2022 | 1 | Manchester City | 38 | 28 | 5 | 5 | 94 | 33 |
| 2022 | 2 | Arsenal | 38 | 26 | 6 | 6 | 88 | 43 |
| 2022 | 3 | Manchester United | 38 | 23 | 6 | 9 | 58 | 43 |
| 2022 | 4 | Newcastle | 38 | 19 | 14 | 5 | 68 | 33 |
| 2022 | 5 | Liverpool | 38 | 19 | 10 | 9 | 75 | 47 |
+------------+---------+-------------------+----------------+------+-------+--------+-----------+---------------+
</pre>
<p><strong>输出:</strong></p>
<pre>
+------------+---------+-------------------+--------+-----------------+------+
| season_id | team_id | team_name | points | goal_difference | rank |
+------------+---------+-------------------+--------+-----------------+------+
| 2021 | 1 | Manchester City | 93 | 73 | 1 |
| 2021 | 2 | Liverpool | 92 | 68 | 2 |
| 2021 | 3 | Chelsea | 74 | 43 | 3 |
| 2021 | 4 | Tottenham | 71 | 29 | 4 |
| 2021 | 5 | Arsenal | 69 | 13 | 5 |
| 2022 | 1 | Manchester City | 89 | 61 | 1 |
| 2022 | 2 | Arsenal | 84 | 45 | 2 |
| 2022 | 3 | Manchester United | 75 | 15 | 3 |
| 2022 | 4 | Newcastle | 71 | 35 | 4 |
| 2022 | 5 | Liverpool | 67 | 28 | 5 |
+------------+---------+-------------------+--------+-----------------+------+
</pre>
<p><strong>解释:</strong></p>
<ul>
<li>对于 2021 赛季:
<ul>
<li>曼城有 93 积分 (29 * 3 + 6 * 1) 以及 73&nbsp;(99 - 26)&nbsp;个净胜球。</li>
<li>利物浦有 92 积分 (28 * 3 + 8 * 1) 以及 68 (94 - 26) 个净胜球。</li>
<li>切尔西有&nbsp;74 积分 (21 * 3 + 11 * 1) 以及 43 (76 - 33)&nbsp;个净胜球。</li>
<li>托特纳姆有 71 积分 (22 * 3 + 5 * 1) 以及 29 (69 - 40)&nbsp;个净胜球。</li>
<li>阿森纳有 69 积分 (22 * 3 + 3 * 1) 以及 13 (61 - 48) 个净胜球。</li>
</ul>
</li>
<li>对于 2022 赛季:
<ul>
<li>曼城有 89 积分 (28 * 3 + 5 * 1) 以及 61 (94 - 33)&nbsp;个净胜球。</li>
<li>阿森纳有 84 积分 (26 * 3 + 6 * 1) 以及 45 (88 - 43)&nbsp;个净胜球。</li>
<li>曼联有&nbsp;75 积分 (23 * 3 + 6 * 1) 以及 15 (58 - 43)&nbsp;个净胜球。</li>
<li>纽卡斯尔有&nbsp;71 积分 (19 * 3 + 14 * 1) 以及 35 (68 - 33)&nbsp;个净胜球。</li>
<li>利物浦有 67 积分 (19 * 3 + 10 * 1) 以及 28 (75 - 47)&nbsp;个净胜球。</li>
</ul>
</li>
<li>球队首先以积分排名,然后是净胜球,最后是球队名称。</li>
<li>输出以 season_id 升序排序,然后以排名升序排序,最后以 team_name 升序排序。</li>
</ul>
<!-- description:end -->
## 解法
<!-- solution:start -->
### 方法一:窗口函数
我们可以使用窗口函数 `RANK()`,将球队按照赛季分组,按照积分、净胜球和球队名称的顺序进行排名。
最后,我们只需要按照 `season_id`、`position` 和 `team_name` 进行排序即可。
<!-- tabs:start -->
#### MySQL
```sql
SELECT
season_id,
team_id,
team_name,
wins * 3 + draws points,
goals_for - goals_against goal_difference,
RANK() OVER (
PARTITION BY season_id
ORDER BY wins * 3 + draws DESC, goals_for - goals_against DESC, team_name
) position
FROM SeasonStats
ORDER BY 1, 6, 3;
```
#### Pandas
```python
import pandas as pd
def process_team_standings(season_stats: pd.DataFrame) -> pd.DataFrame:
season_stats["points"] = season_stats["wins"] * 3 + season_stats["draws"]
season_stats["goal_difference"] = (
season_stats["goals_for"] - season_stats["goals_against"]
)
season_stats = season_stats.sort_values(
["season_id", "points", "goal_difference", "team_name"],
ascending=[True, False, False, True],
)
season_stats["position"] = season_stats.groupby("season_id").cumcount() + 1
return season_stats[
["season_id", "team_id", "team_name", "points", "goal_difference", "position"]
]
```
<!-- tabs:end -->
<!-- solution:end -->
<!-- problem:end -->

View File

@ -0,0 +1,188 @@
---
comments: true
difficulty: Medium
edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3322.Premier%20League%20Table%20Ranking%20III/README_EN.md
tags:
- Database
---
<!-- problem:start -->
# [3322. Premier League Table Ranking III 🔒](https://leetcode.com/problems/premier-league-table-ranking-iii)
[中文文档](/solution/3300-3399/3322.Premier%20League%20Table%20Ranking%20III/README.md)
## Description
<!-- description:start -->
<p>Table: <code>SeasonStats</code></p>
<pre>
+------------------+---------+
| Column Name | Type |
+------------------+---------+
| season_id | int |
| team_id | int |
| team_name | varchar |
| matches_played | int |
| wins | int |
| draws | int |
| losses | int |
| goals_for | int |
| goals_against | int |
+------------------+---------+
(season_id, team_id) is the unique key for this table.
This table contains season id, team id, team name, matches played, wins, draws, losses, goals scored (goals_for), and goals conceded (goals_against) for each team in each season.
</pre>
<p>Write a solution to calculate the <strong>points</strong>, <strong>goal difference</strong>, and <strong>rank</strong> for <strong>each team</strong> in <strong>each season</strong>. The ranking should be determined as follows:</p>
<ul>
<li>Teams are first ranked by their total points (highest to lowest)</li>
<li>If points are tied, teams are then ranked by their goal difference (highest to lowest)</li>
<li>If goal difference is also tied, teams are then ranked alphabetically by team name</li>
</ul>
<p>Points are calculated as follows:</p>
<ul>
<li><code>3</code> points for a <strong>win</strong></li>
<li><code>1</code> point for a <strong>draw</strong></li>
<li><code>0</code> points for a <strong>loss</strong></li>
</ul>
<p>Goal difference is calculated as: <code>goals_for - goals_against</code></p>
<p>Return <em>the result table ordered&nbsp;by</em> <code>season_id</code> <em>in <strong>ascending</strong> order, then by</em> <code>rank</code> <em>in <strong>ascending</strong> order, and finally by</em> <code>team_name</code> <em>in <strong>ascending</strong> order.</em></p>
<p>The query result format is in the following example.</p>
<p>&nbsp;</p>
<p><strong class="example">Example:</strong></p>
<p><strong>Input:</strong></p>
<p><code>SeasonStats</code> table:</p>
<pre>
+------------+---------+-------------------+----------------+------+-------+--------+-----------+---------------+
| season_id | team_id | team_name | matches_played | wins | draws | losses | goals_for | goals_against |
+------------+---------+-------------------+----------------+------+-------+--------+-----------+---------------+
| 2021 | 1 | Manchester City | 38 | 29 | 6 | 3 | 99 | 26 |
| 2021 | 2 | Liverpool | 38 | 28 | 8 | 2 | 94 | 26 |
| 2021 | 3 | Chelsea | 38 | 21 | 11 | 6 | 76 | 33 |
| 2021 | 4 | Tottenham | 38 | 22 | 5 | 11 | 69 | 40 |
| 2021 | 5 | Arsenal | 38 | 22 | 3 | 13 | 61 | 48 |
| 2022 | 1 | Manchester City | 38 | 28 | 5 | 5 | 94 | 33 |
| 2022 | 2 | Arsenal | 38 | 26 | 6 | 6 | 88 | 43 |
| 2022 | 3 | Manchester United | 38 | 23 | 6 | 9 | 58 | 43 |
| 2022 | 4 | Newcastle | 38 | 19 | 14 | 5 | 68 | 33 |
| 2022 | 5 | Liverpool | 38 | 19 | 10 | 9 | 75 | 47 |
+------------+---------+-------------------+----------------+------+-------+--------+-----------+---------------+
</pre>
<p><strong>Output:</strong></p>
<pre>
+------------+---------+-------------------+--------+-----------------+------+
| season_id | team_id | team_name | points | goal_difference | rank |
+------------+---------+-------------------+--------+-----------------+------+
| 2021 | 1 | Manchester City | 93 | 73 | 1 |
| 2021 | 2 | Liverpool | 92 | 68 | 2 |
| 2021 | 3 | Chelsea | 74 | 43 | 3 |
| 2021 | 4 | Tottenham | 71 | 29 | 4 |
| 2021 | 5 | Arsenal | 69 | 13 | 5 |
| 2022 | 1 | Manchester City | 89 | 61 | 1 |
| 2022 | 2 | Arsenal | 84 | 45 | 2 |
| 2022 | 3 | Manchester United | 75 | 15 | 3 |
| 2022 | 4 | Newcastle | 71 | 35 | 4 |
| 2022 | 5 | Liverpool | 67 | 28 | 5 |
+------------+---------+-------------------+--------+-----------------+------+
</pre>
<p><strong>Explanation:</strong></p>
<ul>
<li>For the 2021 season:
<ul>
<li>Manchester City has 93 points (29 * 3 + 6 * 1) and a goal difference of 73 (99 - 26).</li>
<li>Liverpool has 92 points (28 * 3 + 8 * 1) and a goal difference of 68 (94 - 26).</li>
<li>Chelsea has 74 points (21 * 3 + 11 * 1) and a goal difference of 43 (76 - 33).</li>
<li>Tottenham has 71 points (22 * 3 + 5 * 1) and a goal difference of 29 (69 - 40).</li>
<li>Arsenal has 69 points (22 * 3 + 3 * 1) and a goal difference of 13 (61 - 48).</li>
</ul>
</li>
<li>For the 2022 season:
<ul>
<li>Manchester City has 89 points (28 * 3 + 5 * 1) and a goal difference of 61 (94 - 33).</li>
<li>Arsenal has 84 points (26 * 3 + 6 * 1) and a goal difference of 45 (88 - 43).</li>
<li>Manchester United has 75 points (23 * 3 + 6 * 1) and a goal difference of 15 (58 - 43).</li>
<li>Newcastle has 71 points (19 * 3 + 14 * 1) and a goal difference of 35 (68 - 33).</li>
<li>Liverpool has 67 points (19 * 3 + 10 * 1) and a goal difference of 28 (75 - 47).</li>
</ul>
</li>
<li>The teams are ranked first by points, then by goal difference, and finally by team name.</li>
<li>The output is ordered by season_id ascending, then by rank ascending, and finally by team_name ascending.</li>
</ul>
<!-- description:end -->
## Solutions
<!-- solution:start -->
### Solution 1: Window Function
We can use the window function `RANK()` to rank the teams by grouping them by season and sorting based on points, goal difference, and team name.
Finally, we just need to sort by `season_id`, `position`, and `team_name`.
<!-- tabs:start -->
#### MySQL
```sql
SELECT
season_id,
team_id,
team_name,
wins * 3 + draws points,
goals_for - goals_against goal_difference,
RANK() OVER (
PARTITION BY season_id
ORDER BY wins * 3 + draws DESC, goals_for - goals_against DESC, team_name
) position
FROM SeasonStats
ORDER BY 1, 6, 3;
```
#### Pandas
```python
import pandas as pd
def process_team_standings(season_stats: pd.DataFrame) -> pd.DataFrame:
season_stats["points"] = season_stats["wins"] * 3 + season_stats["draws"]
season_stats["goal_difference"] = (
season_stats["goals_for"] - season_stats["goals_against"]
)
season_stats = season_stats.sort_values(
["season_id", "points", "goal_difference", "team_name"],
ascending=[True, False, False, True],
)
season_stats["position"] = season_stats.groupby("season_id").cumcount() + 1
return season_stats[
["season_id", "team_id", "team_name", "points", "goal_difference", "position"]
]
```
<!-- tabs:end -->
<!-- solution:end -->
<!-- problem:end -->

View File

@ -0,0 +1,19 @@
import pandas as pd
def process_team_standings(season_stats: pd.DataFrame) -> pd.DataFrame:
season_stats["points"] = season_stats["wins"] * 3 + season_stats["draws"]
season_stats["goal_difference"] = (
season_stats["goals_for"] - season_stats["goals_against"]
)
season_stats = season_stats.sort_values(
["season_id", "points", "goal_difference", "team_name"],
ascending=[True, False, False, True],
)
season_stats["position"] = season_stats.groupby("season_id").cumcount() + 1
return season_stats[
["season_id", "team_id", "team_name", "points", "goal_difference", "position"]
]

View File

@ -0,0 +1,12 @@
SELECT
season_id,
team_id,
team_name,
wins * 3 + draws points,
goals_for - goals_against goal_difference,
RANK() OVER (
PARTITION BY season_id
ORDER BY wins * 3 + draws DESC, goals_for - goals_against DESC, team_name
) position
FROM SeasonStats
ORDER BY 1, 6, 3;

View File

@ -297,6 +297,7 @@
| 3278 | [寻找数据科学家职位的候选人 II](/solution/3200-3299/3278.Find%20Candidates%20for%20Data%20Scientist%20Position%20II/README.md) | `数据库` | 中等 | 🔒 |
| 3293 | [计算产品最终价格](/solution/3200-3299/3293.Calculate%20Product%20Final%20Price/README.md) | `数据库` | 中等 | 🔒 |
| 3308 | [Find Top Performing Driver](/solution/3300-3399/3308.Find%20Top%20Performing%20Driver/README.md) | `数据库` | 中等 | 🔒 |
| 3322 | [英超积分榜排名 III](/solution/3300-3399/3322.Premier%20League%20Table%20Ranking%20III/README.md) | | 中等 | 🔒 |
## 版权

View File

@ -295,6 +295,7 @@ Press <kbd>Control</kbd> + <kbd>F</kbd>(or <kbd>Command</kbd> + <kbd>F</kbd> on
| 3278 | [Find Candidates for Data Scientist Position II](/solution/3200-3299/3278.Find%20Candidates%20for%20Data%20Scientist%20Position%20II/README_EN.md) | `Database` | Medium | 🔒 |
| 3293 | [Calculate Product Final Price](/solution/3200-3299/3293.Calculate%20Product%20Final%20Price/README_EN.md) | `Database` | Medium | 🔒 |
| 3308 | [Find Top Performing Driver](/solution/3300-3399/3308.Find%20Top%20Performing%20Driver/README_EN.md) | `Database` | Medium | 🔒 |
| 3322 | [Premier League Table Ranking III](/solution/3300-3399/3322.Premier%20League%20Table%20Ranking%20III/README_EN.md) | | Medium | 🔒 |
## Copyright

View File

@ -3332,6 +3332,7 @@
| 3319 | [第 K 大的完美二叉子树的大小](/solution/3300-3399/3319.K-th%20Largest%20Perfect%20Subtree%20Size%20in%20Binary%20Tree/README.md) | | 中等 | 第 419 场周赛 |
| 3320 | [统计能获胜的出招序列数](/solution/3300-3399/3320.Count%20The%20Number%20of%20Winning%20Sequences/README.md) | | 困难 | 第 419 场周赛 |
| 3321 | [计算子数组的 x-sum II](/solution/3300-3399/3321.Find%20X-Sum%20of%20All%20K-Long%20Subarrays%20II/README.md) | | 困难 | 第 419 场周赛 |
| 3322 | [英超积分榜排名 III](/solution/3300-3399/3322.Premier%20League%20Table%20Ranking%20III/README.md) | | 中等 | 🔒 |
## 版权

View File

@ -3330,6 +3330,7 @@ Press <kbd>Control</kbd> + <kbd>F</kbd>(or <kbd>Command</kbd> + <kbd>F</kbd> on
| 3319 | [K-th Largest Perfect Subtree Size in Binary Tree](/solution/3300-3399/3319.K-th%20Largest%20Perfect%20Subtree%20Size%20in%20Binary%20Tree/README_EN.md) | | Medium | Weekly Contest 419 |
| 3320 | [Count The Number of Winning Sequences](/solution/3300-3399/3320.Count%20The%20Number%20of%20Winning%20Sequences/README_EN.md) | | Hard | Weekly Contest 419 |
| 3321 | [Find X-Sum of All K-Long Subarrays II](/solution/3300-3399/3321.Find%20X-Sum%20of%20All%20K-Long%20Subarrays%20II/README_EN.md) | | Hard | Weekly Contest 419 |
| 3322 | [Premier League Table Ranking III](/solution/3300-3399/3322.Premier%20League%20Table%20Ranking%20III/README_EN.md) | | Medium | 🔒 |
## Copyright