LeeCode 91双周赛复盘
T1: 不同的平均值数目
思路:排序 + 双指针 + 哈希存储
public int distinctAverages(int[] nums) {
Arrays.sort(nums);
Set<Double> set = new HashSet<>();
int i = 0, j = nums.length - 1;
while (i < j) {
double mid = (nums[i] + nums[j]) / 2.0;
if (!set.contains(mid)) {
set.add(mid);
}
i += 1;
j -= 1;
}
return set.size();
}
T2: 统计构造好字符串的方案数
思路:动态规划
-
状态定义:
dp[i]
表示长度为i
字符串的构造方案数 -
初始状态:
dp[0] = 1
表示空白字符串方案数为 1 -
状态转移: \(dp[i] = (dp[i - zero] + dp[i - one]) \% MOD\)
public static final int MOD = 1000000007;
public int countGoodStrings(int low, int high, int zero, int one) {
int res = 0;
int[] dp = new int[high + 1];
dp[0] = 1;
for (int i = 1; i <= high; ++i) {
if (i >= zero) {
dp[i] = (dp[i] + dp[i - zero]) % MOD;
}
if (i >= one) {
dp[i] = (dp[i] + dp[i - one]) % MOD;
}
if (i >= low) {
res = (res + dp[i]) % MOD;
}
}
return res;
}
T3: 树上最大得分和路径
思路:两次DFS
-
第一次DFS,记录Bob经过每个点的时间
-
第二次DFS,记录Alice到每个叶节点,计算最大值
public int ans = Integer.MIN_VALUE;
public int mostProfitablePath(int[][] edges, int bob, int[] amount) {
// Build Tree
int n = amount.length;
List<Integer>[] tree = new List[n];
for (int i = 0; i < n; i++) {
tree[i] = new ArrayList<>();
}
for (int[] edge : edges) {
int x = edge[0];
int y = edge[1];
tree[x].add(y);
tree[y].add(x);
}
int[] bobTime = new int[n];
Arrays.fill(bobTime, n);
dfs_bob(tree, bobTime, bob, -1, 0);
// 区分根节点与叶子节点
tree[0].add(-1);
dfs_alice(tree, amount, bobTime, 0, -1, 0, 0);
return ans;
}
/**
*
* @param tree:树
* @param bobTime:bob路径上经过每个节点的时间数组
* @param cur:当前节点
* @param last:上一个节点
* @param t:当前时间
* @return
*/
public boolean dfs_bob(List<Integer>[] tree, int[] bobTime, int cur, int last, int t) {
if (cur == 0) {
bobTime[cur] = t;
return true;
}
for (int next : tree[cur]) {
// 可用顺利走到根节点的路径才标记
// next != last: 避免循环访问
if (next != last && dfs_bob(tree, bobTime, next, cur, t + 1)) {
bobTime[cur] = t;
return true;
}
}
return false;
}
/**
*
* @param tree: 树
* @param amount: 分值数组
* @param bobTime: bob路径上经过每个节点的时间数组
* @param cur: 当前节点
* @param last: 上一个节点
* @param t: 时间
* @param temp: 当前路径分值
*/
public void dfs_alice(List<Integer>[] tree, int[] amount, int[] bobTime, int cur, int last, int t, int temp) {
if (t < bobTime[cur]) {
temp += amount[cur];
}
else if (t == bobTime[cur]) {
temp += amount[cur] / 2;
}
// 到达叶节点
if (tree[cur].size() == 1) {
ans = Math.max(ans, temp);
return;
}
for (int next : tree[cur]) {
if (next != last) {
dfs_alice(tree, amount, bobTime, next, cur, t + 1, temp);
}
}
}
T4: 根据限制分割消息
思路:枚举分割个数 i
,计算每个个数能容纳的字符总数,得到 message
需要的分割个数
public String[] splitMessage(String message, int limit) {
int n = message.length();
// 枚举分割个数 i, 计算其容量
int i = 1;
int cap = 0;
int tail_length = 0;
// cap >= n, 则说明该分割次数符合要求
while (true) {
if (i < 10) {
tail_length = 5;
}
else if (i < 100) {
if (i == 10) {
cap -= 9;
}
tail_length = 7;
}
else if (i < 1000) {
if (i == 100) {
cap -= 99;
}
tail_length = 9;
}
else {
if (i == 1000) {
cap -= 999;
}
tail_length = 11;
}
// tail长度大于等于limit, 则无法分割
if (tail_length >= limit) {
return new String[]{};
}
cap += limit - tail_length;
if (cap >= n) {
break;
}
i += 1;
}
String[] ans = new String[i];
int index = 0;
for (int j = 0; j < i; j++) {
String tail = "<" + (j + 1) + "/" + i + ">";
if (j == i - 1) {
ans[j] = message.substring(index) + tail;
}
else {
int len = limit - tail.length();
ans[j] = message.substring(index, index + len) + tail;
index += len;
}
}
return ans;
}