2022-6-26 黑名单中的随机数,不同骰子序列的数目,操作后的最大异或和,统计无向图中无法互相到达点对数,二维网格图中探测环,检查网格中是否存在有效路径,交换字符串中的元素

1. 黑名单中的随机数

You are given an integer n and an array of unique integers blacklist. Design an algorithm to pick a random integer in the range [0, n - 1] that is not in blacklist. Any integer that is in the mentioned range and not in blacklist should be equally likely to be returned.

Optimize your algorithm such that it minimizes the number of calls to the built-in random function of your language.

Implement the Solution class:

  • Solution(int n, int[] blacklist) Initializes the object with the integer n and the blacklisted integers blacklist.
  • int pick() Returns a random integer in the range [0, n - 1] and not in blacklist.

Example

Input
["Solution", "pick", "pick", "pick", "pick", "pick", "pick", "pick"]
[[7, [2, 3, 5]], [], [], [], [], [], [], []]
Output
[null, 0, 4, 1, 6, 1, 0, 4]

代码 [哈希]

class Solution {
private:
    unordered_map<int, int> mp; // black -> white
    default_random_engine generator;
    uniform_int_distribution<int> distr;

public:
    Solution(int n, vector<int> &blacklist) {
        unordered_set<int> black, white;
        int bound = n - blacklist.size();
        for (int x:blacklist) {
            if (x >= bound) black.insert(x);
            if (x < bound) white.insert(x);
        }
        int i = bound;
        for (auto x:white) {
            while (black.count(i)) ++i;
            mp[x] = i++;
        }
        distr = uniform_int_distribution<int>(0, bound - 1);
    }

    int pick() {
        int x = distr(generator);
        return mp.count(x) ? mp[x] : x;
    }
};

2. 不同骰子序列的数目

You are given an integer n. You roll a fair 6-sided dice n times. Determine the total number of distinct sequences of rolls possible such that the following conditions are satisfied:

  1. The greatest common divisor of any adjacent values in the sequence is equal to 1.
  2. There is at least a gap of 2 rolls between equal valued rolls. More formally, if the value of the ith roll is equal to the value of the jth roll, then abs(i - j) > 2.

Return the total number of distinct sequences possible. Since the answer may be very large, return it modulo 109 + 7.

Two sequences are considered distinct if at least one element is different.

Example

Input: n = 4
Output: 184

代码 [动态规划]

class Solution {
public:
    int distinctSequences(int n) {
        if (n == 1) return 6;
        vector<unordered_set<int>> pp{{}, // 通过 __gcd(x,y) 求出与自身不同的最大公约数为1的选择
                                      {2, 3, 4, 5, 6},
                                      {1, 3, 5},
                                      {1, 2, 4, 5},
                                      {1, 3, 5},
                                      {1, 2, 3, 4, 6},
                                      {1, 5}};
        vector<vector<vector<long long>>> dp(n + 1, vector<vector<long long>>(7, vector<long long>(7, 0)));
        for (int j = 1; j <= 6; ++j) {
            for (int k:pp[j]) {
                dp[2][j][k] = 1;
            }
        }
        for (int i = 3; i <= n; ++i) {
            for (int j = 1; j <= 6; ++j) {
                for (auto k:pp[j]) {
                    for (int prev = 1; prev <= 6; ++prev) {
                        if (prev == j) continue;
                        dp[i][j][k] += dp[i - 1][k][prev] % 1000000007;
                    }
                }
            }
        }
        long long ans = 0;
        for (int j = 1; j <= 6; ++j) {
            for (int k = 1; k <= 6; ++k) {
                ans += dp[n][j][k];
                ans %= 1000000007;
            }
        }
        return ans;
    }
};

3. 操作后的最大异或和

You are given a 0-indexed integer array nums. In one operation, select any non-negative integer x and an index i, then update nums[i] to be equal to nums[i] AND (nums[i] XOR x).

Note that AND is the bitwise AND operation and XOR is the bitwise XOR operation.

Return the maximum possible bitwise XOR of all elements of nums after applying the operation any number of times.

Example

Input: nums = [3,2,4,6]
Output: 7

代码 [位运算]

class Solution {
public:
    int maximumXOR(const vector<int> &nums) {
        int ans = 0;
        for (int x:nums) ans |= x;
        return ans;
    }
};

4. 统计无向图中无法互相到达点对数

You are given an integer n. There is an undirected graph with n nodes, numbered from 0 to n - 1. You are given a 2D integer array edges where edges[i] = [ai, bi] denotes that there exists an undirected edge connecting nodes ai and bi.

Return the number of pairs of different nodes that are unreachable from each other.

Example

Input: n = 3, edges = [[0,1],[0,2],[1,2]]
Output: 0

代码 [并查集]

class Solution {
private:
    vector<int> parent;

    void initial(int n) {
        parent.resize(n);
        for (int i = 0; i < n; i++) parent[i] = i;
    }

    int find(int x) {
        while (x != parent[x]) {
            parent[x] = parent[parent[x]];
            x = parent[x];
        }
        return x;
    }

    void unite(int x1, int x2) {
        int r1 = find(x1), r2 = find(x2);
        if (r1 != r2) parent[r1] = r2;
    }

public:
    long long countPairs(int n, const vector<vector<int>> &edges) {
        initial(n);
        for (auto &edge:edges) {
            unite(edge[0], edge[1]);
        }
        unordered_map<int, long long> mp;
        for (int x:parent) {
            mp[find(x)]++;
        }
        long long accu = 0, ans = 0;
        for (auto[_, x]:mp) {
            ans += accu * x;
            accu += x;
        }
        return ans;
    }
};

5. 二维网格图中探测环

Given a 2D array of characters grid of size m x n, you need to find if there exists any cycle consisting of the same value in grid.

A cycle is a path of length 4 or more in the grid that starts and ends at the same cell. From a given cell, you can move to one of the cells adjacent to it - in one of the four directions (up, down, left, or right), if it has the same value of the current cell.

Also, you cannot move to the cell that you visited in your last move. For example, the cycle (1, 1) -> (1, 2) -> (1, 1) is invalid because from (1, 2) we visited (1, 1) which was the last visited cell.

Return true if any cycle of the same value exists in grid, otherwise, return false.

Example

Input: grid = [["a","a","a","a"],["a","b","b","a"],["a","b","b","a"],["a","a","a","a"]]
Output: true

代码 [并查集]

class Solution {
private:
    int parent[1 << 18];
    const int DIR[2][2]{{1, 0}, {0, 1}};

    void initial() {
        for (int i = 0; i < (1 << 18); i++) parent[i] = i;
    }

    int find(int x) {
        while (x != parent[x]) {
            parent[x] = parent[parent[x]];
            x = parent[x];
        }
        return x;
    }

    bool unite(int x1, int x2) {
        int r1 = find(x1), r2 = find(x2);
        if (r1 == r2) return false;
        parent[r1] = r2;
        return true;
    }

public:
    bool containsCycle(const vector<vector<char>> &grid) {
        initial();
        int m = grid.size(), n = grid[0].size();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                for (int k = 0; k < 2; ++k) {
                    int ni = i + DIR[k][0], nj = j + DIR[k][1];
                    if (ni == m || nj == n || grid[i][j] != grid[ni][nj]) continue;
                    if (!unite(i << 9 | j, ni << 9 | nj)) return true;
                }
            }
        }
        return false;
    }
};

6. 检查网格中是否存在有效路径

You are given an m x n grid. Each cell of grid represents a street. The street of grid[i][j] can be:

  • 1 which means a street connecting the left cell and the right cell.
  • 2 which means a street connecting the upper cell and the lower cell.
  • 3 which means a street connecting the left cell and the lower cell.
  • 4 which means a street connecting the right cell and the lower cell.
  • 5 which means a street connecting the left cell and the upper cell.
  • 6 which means a street connecting the right cell and the upper cell.

Example

Input: grid = [[2,4,3],[6,5,2]]
Output: true

代码 [并查集]

class Solution {
private:
    int parent[1 << 18];
    const int DIR[2][2]{{1, 0}, {0, 1}};

    void initial() {
        for (int i = 0; i < (1 << 18); i++) parent[i] = i;
    }

    int find(int x) {
        while (x != parent[x]) {
            parent[x] = parent[parent[x]];
            x = parent[x];
        }
        return x;
    }

    bool unite(int x1, int x2) {
        int r1 = find(x1), r2 = find(x2);
        if (r1 == r2) return false;
        parent[r1] = r2;
        return true;
    }

public:
    bool hasValidPath(const vector<vector<int>> &grid) {
        initial();
        int m = grid.size(), n = grid[0].size();
        vector<unordered_set<int>> connect{{2, 3, 4},
                                           {2, 5, 6},
                                           {1, 4, 6},
                                           {1, 3, 5}};
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                for (int k = 0; k < 2; ++k) {
                    int ni = i + DIR[k][0], nj = j + DIR[k][1];
                    if (ni == m || nj == n) continue;
                    if (connect[k << 1].count(grid[i][j]) && connect[(k << 1) + 1].count(grid[ni][nj]))
                        unite(i << 9 | j, ni << 9 | nj);
                }
            }
        }
        return find(0) == find((m - 1) << 9 | (n - 1));
    }
};

7. 交换字符串中的元素

给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。

你可以 任意多次交换pairs 中任意一对索引处的字符。

返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。

输入:s = "dcab", pairs = [[0,3],[1,2]]
输出:"bacd"

代码 [并查集]

class Solution {
private:
    int parent[100000];

    void initial() {
        for (int i = 0; i < 100000; i++) parent[i] = i;
    }

    int find(int x) {
        while (x != parent[x]) {
            parent[x] = parent[parent[x]];
            x = parent[x];
        }
        return x;
    }

    void unite(int x1, int x2) {
        int r1 = find(x1), r2 = find(x2);
        if (r1 != r2) parent[r1] = r2;
    }

public:
    string smallestStringWithSwaps(string &s, const vector<vector<int>> &pairs) {
        initial();
        for (auto &p:pairs) unite(p[0], p[1]);
        unordered_map<int, set<int>> mp;
        for (int i = 0; i < s.size(); ++i) {
            mp[find(i)].insert(i);
        }
        for (auto&[_, us]:mp) {
            string sub;
            for (int i:us) sub.push_back(s[i]);
            sort(sub.begin(), sub.end());
            int j = 0;
            for (int i:us) s[i] = sub[j++];
        }
        return s;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值