Skip to content

Commit

Permalink
feat: add solutions to lc problem: No.1366
Browse files Browse the repository at this point in the history
No.1366.Rank Teams by Votes
  • Loading branch information
yanglbme committed Dec 29, 2024
1 parent 73793ca commit 9211c55
Show file tree
Hide file tree
Showing 12 changed files with 306 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ tags:

### 方法一:双指针

我们使用两个指针 $a$, $b$ 分别指向两个链表 $headA$, $headB$。
我们使用两个指针 $a$, $b$ 分别指向两个链表 $\textit{headA}$, $\textit{headB}$。

同时遍历链表,当 $a$ 到达链表 $headA$ 的末尾时,重新定位到链表 $headB$ 的头节点;当 $b$ 到达链表 $headB$ 的末尾时,重新定位到链表 $headA$ 的头节点。
同时遍历链表,当 $a$ 到达链表 $\textit{headA}$ 的末尾时,重新定位到链表 $\textit{headB}$ 的头节点;当 $b$ 到达链表 $\textit{headB}$ 的末尾时,重新定位到链表 $\textit{headA}$ 的头节点。

若两指针相遇,所指向的结点就是第一个公共节点。若没相遇,说明两链表无公共节点,此时两个指针都指向 `null`,返回其中一个即可。

时间复杂度 $O(m+n)$,其中 $m$ 和 $n$ 分别是链表 $headA$ 和 $headB$ 的长度。空间复杂度 $O(1)$。
时间复杂度 $O(m + n)$,其中 $m$ 和 $n$ 分别是链表 $\textit{headA}$ 和 $\textit{headB}$ 的长度。空间复杂度 $O(1)$。

<!-- tabs:start -->

Expand Down Expand Up @@ -233,9 +233,8 @@ func getIntersectionNode(headA, headB *ListNode) *ListNode {
*/

function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null {
let a = headA;
let b = headB;
while (a != b) {
let [a, b] = [headA, headB];
while (a !== b) {
a = a ? a.next : headB;
b = b ? b.next : headA;
}
Expand All @@ -260,9 +259,8 @@ function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): Li
* @return {ListNode}
*/
var getIntersectionNode = function (headA, headB) {
let a = headA;
let b = headB;
while (a != b) {
let [a, b] = [headA, headB];
while (a !== b) {
a = a ? a.next : headB;
b = b ? b.next : headA;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ Explanation: The two lists do not intersect, so return null.

### Solution 1: Two Pointers

We use two pointers $a$ and $b$ to point to two linked lists $headA$ and $headB$ respectively.
We use two pointers $a$ and $b$ to point to the heads of the two linked lists $\textit{headA}$ and $\textit{headB}$, respectively.

We traverse the linked lists simultaneously. When $a$ reaches the end of the linked list $headA$, it is repositioned to the head node of the linked list $headB$. When $b$ reaches the end of the linked list $headB$, it is repositioned to the head node of the linked list $headA$.
Traverse the linked lists simultaneously. When $a$ reaches the end of $\textit{headA}$, redirect it to the head of $\textit{headB}$. Similarly, when $b$ reaches the end of $\textit{headB}$, redirect it to the head of $\textit{headA}$.

If the two pointers meet, the node they point to is the first common node. If they don't meet, it means that the two linked lists have no common nodes. At this time, both pointers point to `null`, and we can return either one.
If the two pointers meet, the node they point to is the first common node. If they do not meet, it means the two linked lists have no common nodes, and both pointers will point to `null`. Return either pointer.

The time complexity is $O(m+n)$, where $m$ and $n$ are the lengths of the linked lists $headA$ and $headB$ respectively. The space complexity is $O(1)$.
The time complexity is $O(m + n)$, where $m$ and $n$ are the lengths of the linked lists $\textit{headA}$ and $\textit{headB}$, respectively. The space complexity is $O(1)$.

<!-- tabs:start -->

Expand Down Expand Up @@ -217,9 +217,8 @@ func getIntersectionNode(headA, headB *ListNode) *ListNode {
*/

function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null {
let a = headA;
let b = headB;
while (a != b) {
let [a, b] = [headA, headB];
while (a !== b) {
a = a ? a.next : headB;
b = b ? b.next : headA;
}
Expand All @@ -244,9 +243,8 @@ function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): Li
* @return {ListNode}
*/
var getIntersectionNode = function (headA, headB) {
let a = headA;
let b = headB;
while (a != b) {
let [a, b] = [headA, headB];
while (a !== b) {
a = a ? a.next : headB;
b = b ? b.next : headA;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
* @return {ListNode}
*/
var getIntersectionNode = function (headA, headB) {
let a = headA;
let b = headB;
while (a != b) {
let [a, b] = [headA, headB];
while (a !== b) {
a = a ? a.next : headB;
b = b ? b.next : headA;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
*/

function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null {
let a = headA;
let b = headB;
while (a != b) {
let [a, b] = [headA, headB];
while (a !== b) {
a = a ? a.next : headB;
b = b ? b.next : headA;
}
Expand Down
138 changes: 98 additions & 40 deletions solution/1300-1399/1366.Rank Teams by Votes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ C 队获得三票「排位第二」,两票「排位第三」。
<strong>输入:</strong>votes = ["WXYZ","XYZW"]
<strong>输出:</strong>"XWYZ"
<strong>解释:</strong>
X 队在并列僵局打破后成为排名第一的团队。X 队和 W 队的「排位第一」票数一样,但是 X 队有一票「排位第二」,而 W 没有获得「排位第二」。
X 队在并列僵局打破后成为排名第一的团队。X 队和 W 队的「排位第一」票数一样,但是 X 队有一票「排位第二」,而 W 没有获得「排位第二」。
</pre>

<p><strong class="example">示例 3:</strong></p>
Expand Down Expand Up @@ -89,7 +89,7 @@ X 队在并列僵局打破后成为排名第一的团队。X 队和 W 队的「

对于每个候选人,我们可以统计他在每个排位上的票数,然后根据不同的排位依次比较票数,票数相同则比较字母。

时间复杂度 $O(n^2 \times \log n)$,空间复杂度 $O(n^2)$。其中 $n$ 为候选人的数量
时间复杂度 $O(n \times m + m^2 \times \log m)$,空间复杂度 $O(m^2)$。其中 $n$ 是 $\textit{votes}$ 的长度,而 $m$ 是候选人的数量,即 $\textit{votes}[0]$ 的长度

<!-- tabs:start -->

Expand All @@ -98,42 +98,41 @@ X 队在并列僵局打破后成为排名第一的团队。X 队和 W 队的「
```python
class Solution:
def rankTeams(self, votes: List[str]) -> str:
n = len(votes[0])
cnt = defaultdict(lambda: [0] * n)
m = len(votes[0])
cnt = defaultdict(lambda: [0] * m)
for vote in votes:
for i, c in enumerate(vote):
cnt[c][i] += 1
return "".join(sorted(votes[0], key=lambda x: (cnt[x], -ord(x)), reverse=True))
return "".join(sorted(cnt, key=lambda c: (cnt[c], -ord(c)), reverse=True))
```

#### Java

```java
class Solution {
public String rankTeams(String[] votes) {
int n = votes[0].length();
int[][] cnt = new int[26][n];
int m = votes[0].length();
int[][] cnt = new int[26][m + 1];
for (var vote : votes) {
for (int i = 0; i < n; ++i) {
cnt[vote.charAt(i) - 'A'][i]++;
for (int i = 0; i < m; ++i) {
++cnt[vote.charAt(i) - 'A'][i];
}
}
Character[] cs = new Character[n];
for (int i = 0; i < n; ++i) {
cs[i] = votes[0].charAt(i);
Character[] s = new Character[m];
for (int i = 0; i < m; ++i) {
s[i] = votes[0].charAt(i);
}
Arrays.sort(cs, (a, b) -> {
Arrays.sort(s, (a, b) -> {
int i = a - 'A', j = b - 'A';
for (int k = 0; k < n; ++k) {
int d = cnt[i][k] - cnt[j][k];
if (d != 0) {
return d > 0 ? -1 : 1;
for (int k = 0; k < m; ++k) {
if (cnt[i][k] != cnt[j][k]) {
return cnt[j][k] - cnt[i][k];
}
}
return a - b;
});
StringBuilder ans = new StringBuilder();
for (char c : cs) {
for (var c : s) {
ans.append(c);
}
return ans.toString();
Expand All @@ -147,25 +146,25 @@ class Solution {
class Solution {
public:
string rankTeams(vector<string>& votes) {
int n = votes[0].size();
int cnt[26][n];
memset(cnt, 0, sizeof cnt);
for (auto& vote : votes) {
for (int i = 0; i < n; ++i) {
cnt[vote[i] - 'A'][i]++;
int m = votes[0].size();
array<array<int, 27>, 26> cnt{};

for (const auto& vote : votes) {
for (int i = 0; i < m; ++i) {
++cnt[vote[i] - 'A'][i];
}
}
string ans = votes[0];
sort(ans.begin(), ans.end(), [&](auto& a, auto& b) {
string s = votes[0];
ranges::sort(s, [&](char a, char b) {
int i = a - 'A', j = b - 'A';
for (int k = 0; k < n; ++k) {
for (int k = 0; k < m; ++k) {
if (cnt[i][k] != cnt[j][k]) {
return cnt[i][k] > cnt[j][k];
}
}
return a < b;
});
return ans;
return string(s.begin(), s.end());
}
};
```
Expand All @@ -174,24 +173,83 @@ public:
```go
func rankTeams(votes []string) string {
cnt := [26][26]int{}
m := len(votes[0])
cnt := [26][27]int{}
for _, vote := range votes {
for i, c := range vote {
cnt[c-'A'][i]++
for i, ch := range vote {
cnt[ch-'A'][i]++
}
}
ans := []byte(votes[0])
sort.Slice(ans, func(i, j int) bool {
cnt1, cnt2 := cnt[ans[i]-'A'], cnt[ans[j]-'A']
for k, a := range cnt1 {
b := cnt2[k]
if a != b {
return a > b
s := []rune(votes[0])
sort.Slice(s, func(i, j int) bool {
a, b := s[i]-'A', s[j]-'A'
for k := 0; k < m; k++ {
if cnt[a][k] != cnt[b][k] {
return cnt[a][k] > cnt[b][k]
}
}
return ans[i] < ans[j]
return s[i] < s[j]
})
return string(ans)
return string(s)
}
```

#### TypeScript

```ts
function rankTeams(votes: string[]): string {
const m = votes[0].length;
const cnt: number[][] = Array.from({ length: 26 }, () => Array(m + 1).fill(0));
for (const vote of votes) {
for (let i = 0; i < m; i++) {
cnt[vote.charCodeAt(i) - 65][i]++;
}
}
const s: string[] = votes[0].split('');
s.sort((a, b) => {
const i = a.charCodeAt(0) - 65;
const j = b.charCodeAt(0) - 65;
for (let k = 0; k < m; k++) {
if (cnt[i][k] !== cnt[j][k]) {
return cnt[j][k] - cnt[i][k];
}
}
return a.localeCompare(b);
});
return s.join('');
}
```

#### Rust

```rust
impl Solution {
pub fn rank_teams(votes: Vec<String>) -> String {
let m = votes[0].len();
let mut cnt = vec![vec![0; m + 1]; 26];

for vote in &votes {
for (i, ch) in vote.chars().enumerate() {
cnt[(ch as u8 - b'A') as usize][i] += 1;
}
}

let mut s: Vec<char> = votes[0].chars().collect();

s.sort_by(|&a, &b| {
let i = (a as u8 - b'A') as usize;
let j = (b as u8 - b'A') as usize;

for k in 0..m {
if cnt[i][k] != cnt[j][k] {
return cnt[j][k].cmp(&cnt[i][k]);
}
}
a.cmp(&b)
});

s.into_iter().collect()
}
}
```

Expand Down
Loading

0 comments on commit 9211c55

Please sign in to comment.