记录一下

几乎是压线 AK,就剩下六分钟

image-20260222115357193

最终排名

image-20260222120055900

Q1

image-20260222115741279

给你一个整数数组 nums,其中 nums[i] 表示在第 i 场比赛中获得的分数。

恰好 有两位玩家。初始时,第一位玩家为 主动玩家,第二位玩家为 被动玩家。

按顺序 将下述规则应用于每场比赛 i:

  • 如果 nums[i] 是奇数,主动玩家和被动玩家互换角色。
  • 在每第 6 场比赛(即比赛索引为 5, 11, 17, … 的比赛中),主动玩家和被动玩家互换角色。
  • 主动玩家参与第 i 场比赛,并获得 nums[i] 分。

返回 分数差,即第一位玩家的 总分 减去第二位玩家的 总分 。

示例 1:

输入: nums = [1,2,3]

输出: 0

解释:

第 0 场比赛:分数为奇数,第二位玩家成为主动玩家,获得 nums[0] = 1 分。 第 1 场比赛:没有交换角色。第二位玩家获得 nums[1] = 2 分。 第 2 场比赛:分数为奇数,第一位玩家成为主动玩家,获得 nums[2] = 3 分。 分数差为 3 - 3 = 0。

示例 2:

输入: nums = [2,4,2,1,2,1]

输出: 4

解释:

第 0 到第 2 场比赛:第一位玩家获得 2 + 4 + 2 = 8 分。 第 3 场比赛:分数为奇数,第二位玩家成为主动玩家,获得 nums[3] = 1 分。 第 4 场比赛:第二位玩家获得 nums[4] = 2 分。 第 5 场比赛:分数为奇数,玩家互换角色。由于这是第 6 场比赛,玩家再次互换角色。第二位玩家获得 nums[5] = 1 分。 分数差为 8 - 4 = 4。

示例 3:

输入: nums = [1]

输出: -1

解释:

第 0 场比赛:分数为奇数,第二位玩家成为主动玩家,获得 nums[0] = 1 分。 分数差为 0 - 1 = -1。

提示:

1 <= nums.length <= 1000 1 <= nums[i] <= 1000

代码

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
class Solution {
public int scoreDifference(int[] nums) {
// 主动玩家
int score_z = 0;
// 被动玩家
int score_b = 0;

// 初始时,第一位玩家是主动玩家
boolean flag = true;

for (int i = 0; i < nums.length; i++) {
// 如果 nums[i] 是奇数,交换角色
if ((nums[i] & 1) == 1){
// 角色交换
flag = !flag;
}

// 每第 6 场比赛(索引 5, 11, 17...),交换角色
// 规则 1 和 规则 2 可能同时发生,导致两次交换抵消了
if ((i + 1) % 6 == 0){
flag = !flag;
}

if(flag){
score_z += nums[i];
}else{
score_b += nums[i];
}
}
return score_z - score_b;
}
}

public class Q1 {
}

Q2

image-20260222115733650

给你一个整数 n

如果一个数字的所有位数的 阶乘 之和 等于 数字本身,则称其为 阶数数字(digitorial)。

判断是否存在 n 的 任意排列(包括原始顺序),可以形成一个 阶数数字。

如果存在这样的 排列,返回 true;否则,返回 false。

注意:

  • 非负整数 x 的 阶乘(记作 x!)是所有小于或等于 x 的正整数的 乘积,且 0! = 1。
  • 排列 是一个数字所有位数的重新排列,且不能以零开头。任何以零开头的排列都是无效的

示例 1:

输入: n = 145

输出: true

解释:

数字 145 本身是一个阶数数字,因为 1! + 4! + 5! = 1 + 24 + 120 = 145。因此,答案为 true。

示例 2:

输入: n = 10

输出: false

解释:

数字 10 不是阶数数字,因为 1! + 0! = 2 不等于 10。同时,排列 “01” 是无效的,因为它以零开头。

提示:

1 <= n <= 109©leetcode

代码

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
public boolean isDigitorialPermutation(int n) {
String temp = String.valueOf(n);

// 预计算阶乘
// 数字排列也不影响阶乘之和吧
int[] steps = new int[10];
steps[0] = 1;
for (int i = 1; i < 10; i++) {
steps[i] = steps[i - 1] * i;
}

// 处理数字的频率
int num = n;
int[] countN = new int[10];
int sum = 0;

while (num > 0) {
int digit = num % 10;
countN[digit]++;
sum += steps[digit]; // 计算阶乘之和
num /= 10;
}

// 判断sum能不能排列成n
// 也就是说,sum的数字组成必须和n一样
int[] countSum = new int[10];
int tempSum = sum;
int digitInSum = 0; // 阶乘之和有几位
while (tempSum > 0) {
int digit = tempSum % 10;
countSum[digit]++;
tempSum /= 10;
digitInSum++;
}

// 验证位数是否匹配
int digitInN = 0;
for (int c : countN){
digitInN += c;
}
if(digitInN != digitInSum){
return false;
}

return Arrays.equals(countN, countSum);
}

Q3

image-20260222115751171

给你两个长度均为 n 的二进制字符串 s 和 t。

你可以按任意顺序 重新排列 t 中的字符,但 s 必须保持不变。

返回一个长度为 n 的 二进制字符串,表示将 s 与重新排列后的 t 进行按位 异或 (XOR) 运算所能获得的 最大 整数值。

示例 1:

输入: s = “101”, t = “011”

输出: “110”

解释:

t 的一个最佳重新排列方式是 “011”。 s 与重新排列后的 t 进行按位异或的结果是 “101” XOR “011” = “110”,这是可能的最大值。

示例 2:

输入: s = “0110”, t = “1110”

输出: “1101”

解释:

t 的一个最佳重新排列方式是 “1011”。 s 与重新排列后的 t 进行按位异或的结果是 “0110” XOR “1011” = “1101”,这是可能的最大值。

示例 3:

输入: s = “0101”, t = “1001”

输出: “1111”

解释:

t 的一个最佳重新排列方式是 “1010”。 s 与重新排列后的 t 进行按位异或的结果是 “0101” XOR “1010” = “1111”,这是可能的最大值。

提示:

1 <= n == s.length == t.length <= 2 * 10^5 s[i] 和 t[i] 不是 ‘0’ 就是 ‘1’。

代码

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
class Solution3 {
// 贪心
// 要让两个二进制字符串异或后更大
// 高位1尽量多
public String maximumXor(String s, String t) {
int n = t.length();

// t串中1和0的数量
int count1t = 0, count0t = 0;
for(char c : t.toCharArray()){
if(c == '1'){
count1t++;
}else{
count0t++;
}
}

// 重排列t
StringBuilder result = new StringBuilder();
for (int i = 0; i < n; i++) {
char curr = s.charAt(i);

// 如果 s 是 0,我们想要 1 来异或出 1
if(curr == '0'){
if(count1t > 0){
result.append('1');
count1t--;
}else{
result.append('0');
count0t--;
}
// 如果 s 是 1,我们想要 0 来异或出 1
}else{
if(count0t > 0){
result.append('0');
count0t--;
}else{
result.append('1');
count1t--;
}
}
}
StringBuilder xorResult = new StringBuilder();
for (int i = 0; i < n; i++) {
int sbit = s.charAt(i) - '0';
int tbit = result.charAt(i) - '0';
int xorBit = sbit ^ tbit;
xorResult.append(xorBit);
}
return xorResult.toString();
}
}

Q4

image-20260222115843946

给你一个整数数组 nums 和一个整数 k。

从初始值 val = 1 开始,从左到右处理 nums。在每个下标 i 处,你必须 恰好选择 以下操作之一:

  • 将 val 乘以 nums[i]。
  • 将 val 除以 nums[i]。
  • 保持 val 不变。

在处理完所有元素后,当且仅当 val 的最终有理数值 恰好 等于 k 时,才认为 val 等于 k。

返回生成 val == k 的 不同 选择序列的数量。

注意:除法是有理数除法(精确除法),而不是整数除法。例如,2 / 4 = 1 / 2。

image-20260222115918427
image-20260222115924176
image-20260222115929067

代码

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import java.util.HashMap;
import java.util.Map;

class Solution4 {
// 每个位置3种处理方式, val 乘以 nums[i],val 除以 nums[i],不变
// 可以看到,每一位最大是6,最小是1,那么任何由 1-6 乘除得到的有理数有一定规律
// 1不共享,2贡献2^1,3贡献3^1,4贡献2^2,5贡献5^1,6贡献2^1*3^1
// 其中有三个质因数
// 一眼DP,开搜
// 算了,Map 记忆化吧

// 质因数分解打表
private final int[][] factor = {
{0, 0, 0}, // 0 (占位)
{0, 0, 0}, // 1
{1, 0, 0}, // 2
{0, 1, 0}, // 3
{2, 0, 0}, // 4
{0, 0, 1}, // 5
{1, 1, 0} // 6
};

// 缓存,index为组合,Long为方案数
private Map<String, Long> ways;

/**
* 记忆化搜索
* @param idx 当前处理的 nums 索引
* @param e2, e3, e5 当前 val 拥有的质指数
* @param t2, t3, t5 目标 k 的质指数
*/
private long search(int[] nums, int idx, int e2, int e3, int e5, int t2, int t3, int t5) {
// 所有数字处理完了,检查
if(idx == nums.length){
return (e2 == t2 && e3 == t3 && e5 == t5) ? 1 : 0;
}

// 序列化当前状态,索引+2+3+5,作为记忆化key
String state = idx + "_" + e2 + "_" + e3 + "_" + e5;
if(ways.containsKey(state)){
// 存在这个状态,直接返回之前的结果
return ways.get(state);
}

// 处理当前位
int val = nums[idx];
int f2 = factor[val][0];
int f3 = factor[val][1];
int f5 = factor[val][2];

long count = 0;

// 乘以 nums[idx],指数相加
count += search(nums, idx + 1, e2 + f2, e3 + f3, e5 + f5, t2, t3, t5);

// 除以 nums[idx],指数相减
count += search(nums, idx + 1, e2 - f2, e3 - f3, e5 - f5, t2, t3, t5);

// 保持不变
count += search(nums, idx + 1, e2, e3, e5, t2, t3, t5);

ways.put(state, count);
return count;
}

public int countSequences(int[] nums, long k) {
ways = new HashMap<>();

// 依次提取 k 中的 2, 3, 5
long tempk = k;
int num2 = 0, num3 = 0, num5 = 0;
while(tempk > 0 && tempk % 2 == 0) { num2++; tempk /= 2; }
while(tempk > 0 && tempk % 3 == 0) { num3++; tempk /= 3; }
while(tempk > 0 && tempk % 5 == 0) { num5++; tempk /= 5; }

// 如果 k 还剩下不能被 2,3,5 整除的部分且不为1,说明 nums 无法通过乘除得到 k
if (tempk != 1){
return 0;
}

// 开搜
return (int)search(nums, 0, 0, 0, 0, num2, num3, num5);
}
}