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
.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;
}
};
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
.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.
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;
}
};
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.
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;
}
};
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.
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;
}
};
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
.
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;
}
};
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.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));
}
};
给你一个字符串 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;
}
};