第一次AK!!!必须纪念一下!!
2413. 最小偶倍数
给你一个正整数 n
,返回 2
和 n
的最小公倍数(正整数)。
示例
输入:n = 5
输出:10
解释:5 和 2 的最小公倍数是 10 。
思路
hello world
级别的签到题。我刚读完题还想着要求一下最大公约数gcd
,然后发现其实gcd
都不用求。
class Solution {
public int smallestEvenMultiple(int n) {
if (n % 2 == 0) return n;
return 2 * n;
}
}
2414. 最长的字母序连续子字符串的长度
字母序连续字符串 是由字母表中连续字母组成的字符串。换句话说,字符串 "abcdefghijklmnopqrstuvwxyz"
的任意子字符串都是 字母序连续字符串 。
- 例如,
"abc"
是一个字母序连续字符串,而"acb"
和"za"
不是。
给你一个仅由小写英文字母组成的字符串 s
,返回其 最长 的 字母序连续子字符串 的长度。
示例
输入:s = "abacaba"
输出:2
解释:共有 4 个不同的字母序连续子字符串 "a"、"b"、"c" 和 "ab" 。
"ab" 是最长的字母序连续子字符串。
思路
直接模拟就可以了,遍历并且对连续字符计数,遇到不连续的字符后清空计数。
class Solution {
public int longestContinuousSubstring(String s) {
int n = s.length();
int ans = 1, cnt = 0, last = 0; //前一个字符
for (int i = 0; i < n; i++) {
if (i == 0) {
cnt++;
last = s.charAt(i) - 'a';
} else {
int u = s.charAt(i) - 'a';
if (u - 1 == last) {
cnt++;
last++;
} else {
ans = Math.max(ans, cnt);
cnt = 1;
last = u;
}
}
}
return Math.max(ans, cnt);
}
}
2415. 反转二叉树的奇数层
给你一棵 完美 二叉树的根节点 root
,请你反转这棵树中每个 奇数 层的节点值。
- 例如,假设第 3 层的节点值是
[2,1,3,4,7,11,29,18]
,那么反转后它应该变成[18,29,11,7,4,3,1,2]
。
反转后,返回树的根节点。
完美 二叉树需满足:二叉树的所有父节点都有两个子节点,且所有叶子节点都在同一层。
节点的 层数 等于该节点到根节点之间的边数。
示例
输入:root = [2,3,5,8,13,21,34]
输出:[2,5,3,8,13,21,34]
解释:
这棵树只有一个奇数层。
在第 1 层的节点分别是 3、5 ,反转后为 5、3 。
思路
先用层序遍历BFS将每一层的节点分别存起来,然后逐层遍历进行翻转。
class Solution {
public TreeNode reverseOddLevels(TreeNode root) {
List<List<TreeNode>> list = new ArrayList<>();
Queue<TreeNode> q = new LinkedList<>();
if (root != null) q.offer(root);
while (!q.isEmpty()) {
int n = q.size();
List<TreeNode> layer = new ArrayList<>();
for (int i = 0; i < n; i++) {
TreeNode x = q.poll();
layer.add(x);
if (x.left != null) q.offer(x.left);
if (x.right != null) q.offer(x.right);
}
list.add(layer);
}
for (int i = 0; i < list.size(); i++) {
if (i + 1 >= list.size()) break; // 不存在下一层了, 直接结束
List<TreeNode> thisLayer = list.get(i);
List<TreeNode> nextLayer = list.get(i + 1);
boolean thisEven = i % 2 == 0;
if (thisEven) {
int iThis = 0, iNext = nextLayer.size() - 1;
while (iThis < thisLayer.size()) {
TreeNode x = thisLayer.get(iThis++);
x.left = nextLayer.get(iNext--);
x.right = nextLayer.get(iNext--);
}
} else {
int iThis = thisLayer.size() - 1, iNext = 0;
while (iThis >= 0) {
TreeNode x = thisLayer.get(iThis--);
x.left = nextLayer.get(iNext++);
x.right = nextLayer.get(iNext++);
}
}
}
return root;
}
}
今天再次读题后,发现只用翻转节点中的值,只用翻转节点中的值的话,节点本身可以完全不用动,代码可以写的更简单
class Solution {
public TreeNode reverseOddLevels(TreeNode root) {
Queue<TreeNode> q = new LinkedList<>();
if (root != null) q.offer(root);
int depth = 0;
while (!q.isEmpty()) {
int n = q.size();
List<TreeNode> layer = new ArrayList<>();
for (int i = 0; i < n; i++) {
TreeNode x = q.poll();
layer.add(x);
if (x.left != null) q.offer(x.left);
if (x.right != null) q.offer(x.right);
}
if (depth % 2 == 1) {
// 奇数层
int i = 0, j = layer.size() - 1;
while (i < j) swap(layer.get(i++), layer.get(j--));
}
depth++;
}
return root;
}
private void swap(TreeNode a, TreeNode b) {
int t = a.val;
a.val = b.val;
b.val = t;
}
}
该题也可以用深搜DFS来做,代码更短,大概思路是:镜像遍历左右两颗子树(y总牛逼!)
class Solution {
private void dfs(TreeNode left, TreeNode right, int depth) {
if (left == null) return ;
if (depth % 2 == 1) {
int t = left.val;
left.val = right.val;
right.val = t;
}
dfs(left.left, right.right, depth + 1);
dfs(left.right, right.left, depth + 1);
}
public TreeNode reverseOddLevels(TreeNode root) {
dfs(root.left, root.right, 1);
return root;
}
}
2416. 字符串的前缀分数和
给你一个长度为 n
的数组 words
,该数组由 非空 字符串组成。
定义字符串 word
的 分数 等于以 word
作为 前缀 的 words[i]
的数目。
- 例如,如果
words = ["a", "ab", "abc", "cab"]
,那么"ab"
的分数是2
,因为"ab"
是"ab"
和"abc"
的一个前缀。
返回一个长度为 n
的数组 answer
,其中 answer[i]
是 words[i]
的每个非空前缀的分数 总和 。
**注意:**字符串视作它自身的一个前缀。
示例
输入:words = ["abc","ab","bc","b"]
输出:[5,4,3,2]
解释:对应每个字符串的答案如下:
- "abc" 有 3 个前缀:"a"、"ab" 和 "abc" 。
- 2 个字符串的前缀为 "a" ,2 个字符串的前缀为 "ab" ,1 个字符串的前缀为 "abc" 。
总计 answer[0] = 2 + 2 + 1 = 5 。
- "ab" 有 2 个前缀:"a" 和 "ab" 。
- 2 个字符串的前缀为 "a" ,2 个字符串的前缀为 "ab" 。
总计 answer[1] = 2 + 2 = 4 。
- "bc" 有 2 个前缀:"b" 和 "bc" 。
- 2 个字符串的前缀为 "b" ,1 个字符串的前缀为 "bc" 。
总计 answer[2] = 2 + 1 = 3 。
- "b" 有 1 个前缀:"b"。
- 2 个字符串的前缀为 "b" 。
总计 answer[3] = 2 。
思路
这次的第四题比较简单,直接用一个裸Trie树就行了。在Trie树上的每一个节点额外维护一下计数信息cnt
,表示有多少个单词经过了这个节点。求解一个单词时,对这个单词所有字符节点的cnt
进行一下累加即可。
class Solution {
// Trie树上的节点
class Node {
int val;
int cnt;
boolean end; // end标记其实没用, 可以去掉
Node[] sons = new Node[26];
Node(int val) {
this.val = val;
this.cnt = 1;
this.end = false;
}
}
// Trie 树根节点
Node root = new Node(-1);
private void add(String s) {
int n = s.length();
Node cur = root;
for (int i = 0; i < n; i++) {
int u = s.charAt(i) - 'a';
if (cur.sons[u] == null) cur.sons[u] = new Node(u);
else cur.sons[u].cnt++;
cur = cur.sons[u];
}
cur.end = true;
}
private int find(String s) {
Node cur = root;
int n = s.length();
int ret = 0;
for (int i = 0; i < n; i++) {
int u = s.charAt(i) - 'a';
cur = cur.sons[u];
ret += cur.cnt;
}
return ret;
}
public int[] sumPrefixScores(String[] words) {
for (String s : words) add(s);
int[] ans = new int[words.length];
for (int i = 0; i < words.length; i++) {
ans[i] = find(words[i]);
}
return ans;
}
}
总结
这周日早上被对象拉着去打羽毛球,可我大抵是病了,心里横竖都想着周赛,这冲动没有来由。
于是背了台轻薄本就出门了。10点半刚好到球场,然后就在球场边的板凳上打起了周赛😂
好在这次周赛难度不大,差不多11点10分的时候做完了4道题,然后就开心的打球去啦!
事后想想,还好我背上了电脑参加了周赛,不然就要错过好不容易的AK的机会!😭