# Leetcode 第267场周赛题解

# Problem A - 买票需要的时间 (opens new window)

# 方法一:模拟

按题意进行模拟。

  • 时间复杂度O(NT)\mathcal{O}(NT)。其中T=tickets[k]T=tickets[k]为第kk个人需要购票的数量。
  • 空间复杂度O(N)\mathcal{O}(N)
参考代码(C++)
class Solution {
public:
    int timeRequiredToBuy(vector<int>& tickets, int k) {
        queue<int> q;
        int n = tickets.size();
        for (int i = 0; i < n; ++i)
            q.emplace(i);
        int t = 0;
        while (tickets[k]) {
            int u = q.front();
            q.pop();
            tickets[u]--;
            t++;
            if (tickets[u])
                q.emplace(u);
        }
        return t;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 方法二:一次遍历

实际上,我们只需要一次遍历就可以解决本题。对于第kk个及之前的人来说,在第kk个人刚好买完时,他们的购票数量为min(tickets[i],tickets[k])\min(tickets[i],tickets[k]);而之后的人,购票数量为min(tickets[i],tickets[k]1)\min(tickets[i],tickets[k]-1)。求和即可得到答案。

  • 时间复杂度O(N)\mathcal{O}(N)
  • 空间复杂度O(N)\mathcal{O}(N)
参考代码(Python 3)
class Solution:
    def timeRequiredToBuy(self, tickets: List[int], k: int) -> int:
        return sum(min(t, tickets[k]) if i <= k else min(t, tickets[k] - 1) for i, t in enumerate(tickets))
1
2
3

# Problem B - 反转偶数长度组的节点 (opens new window)

# 方法一:模拟

我们可以将链表转换成数组后按要求进行反转,最后再更新链表中的数值即可。

  • 时间复杂度O(N)\mathcal{O}(N)
  • 空间复杂度O(N)\mathcal{O}(N)
参考代码(C++)
class Solution {
public:
    ListNode* reverseEvenLengthGroups(ListNode* head) {
        vector<int> v;
        ListNode *p = head;
        while (p != nullptr) {
            v.emplace_back(p->val);
            p = p->next;
        }
        
        int n = v.size();
        int i = 0, g = 1;
        while (i < n) {
            if (g > n - i)
                g = n - i;
            if (g % 2 == 0)
                reverse(v.begin() + i, v.begin() + i + g);
            i += g;
            g++;
        }
        
        p = head;
        for (int vi : v) {
            p->val = vi;
            p = p->next;
        }
        
        return head;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# Problem C - 解码斜向换位密码 (opens new window)

# 方法一:模拟

理清题意后可知,我们由加密后字符串的长度和行数就可以求得矩阵的列数,然后沿着对角线方向依次取出字符即可。

因为题目说明了答案唯一且结尾不为空格,我们将上面操作得到的字符串末尾的空格全部去除即可得到答案。

  • 时间复杂度O(S)\mathcal{O}(|S|)
  • 空间复杂度O(S)\mathcal{O}(|S|)
参考代码(C++)
class Solution {
public:
    string decodeCiphertext(string encodedText, int rows) {
        int n = encodedText.size();
        int cols = n / rows;
        string ans;
        for (int i = 0; i < cols; ++i) {
            for (int j = 0; j < rows; ++j) {
                if (i + j >= cols)
                    break;
                int idx = j * cols + i + j;
                ans.push_back(encodedText[idx]);
            }
        }
        while (!ans.empty() && ans.back() == ' ')
            ans.pop_back();
        return ans;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Problem D - 处理含限制条件的好友请求 (opens new window)

# 方法一:并查集

容易想到用并查集来维护好友关系。问题是如何处理限制条件。

假设当前好友请求为(u,v)(u,v),对于(p,q)(p,q)这样一条限制条件来说,连接(u,v)(u,v)而导致(p,q)(p,q)相连,有两种情况:

  1. (u,p)(u,p)已经相连,(v,q)(v,q)已经相连
  2. (u,q)(u,q)已经相连,(v,p)(v,p)已经相连

如果这两种情况都得到排除,则这一条限制条件就不会被违反。

  • 时间复杂度O(QRα(N))\mathcal{O}(QR\alpha(N))。其中QQ为查询数,RR为限制数,NN为用户数,α(x)\alpha(x)为Ackerman函数的反函数,在本题的数据范围内可近似认为常数。
  • 空间复杂度O(Q+N)\mathcal{O}(Q+N)
参考代码(C++)
class UnionFind {
  int n;
  vector<int> parent, size;

public:
  UnionFind(int n) {
    this->n = n;
    parent = vector<int>(n);
    size = vector<int>(n, 1);
    for (int i = 0; i < n; ++i)
      parent[i] = i;
  }

  int find(int idx) {
    if (parent[idx] == idx)
      return idx;
    return parent[idx] = find(parent[idx]);
  }

  void connect(int a, int b) {
    int fa = find(a), fb = find(b);
    if (fa != fb) {
      if (size[fa] > size[fb]) {
        parent[fb] = fa;
        size[fa] += size[fb];
      } else {
        parent[fa] = fb;
        size[fb] += size[fa];
      }
    }
  }
};

class Solution {
public:
    vector<bool> friendRequests(int n, vector<vector<int>>& restrictions, vector<vector<int>>& requests) {
        vector<bool> ans;
        
        UnionFind uf(n);
        
        for (auto &req : requests) {
            int u = req[0], v = req[1];
            if (uf.find(u) == uf.find(v))
                ans.push_back(true);
            else {
                bool valid = true;
                for (auto &res : restrictions) {
                    int p = res[0], q = res[1];
                    if ((uf.find(u) == uf.find(p) && uf.find(v) == uf.find(q))
                        || (uf.find(u) == uf.find(q) && uf.find(v) == uf.find(p))) {
                        valid = false;
                        break;
                    }
                }
                if (valid) {
                    uf.connect(u, v);
                    ans.push_back(true);
                } else
                    ans.push_back(false);
            }
        }
        
        return ans;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65