竞赛链接
新鲜出炉今天的周赛, 这场周赛难度没有很大, 但是当时做的时候第二题都错了两次, 直接影响了后面两题的心态…最后排到 200 多名, 只能拿参与奖了 不过还是要赞下新功能一键填入示例, 终于不需要每次手动把测试用例输入进去了, 懒人福音啊…
题目难度: 简单
原题链接
给你一个字符串 sentence 作为句子并指定检索词为 searchWord ,其中句子由若干用 单个空格 分隔的单词组成。
请你检查检索词 searchWord 是否为句子 sentence 中任意单词的前缀。
如果 searchWord 是某一个单词的前缀,则返回句子 sentence 中该单词所对应的下标(下标从 1 开始)。
如果 searchWord 是多个单词的前缀,则返回匹配的第一个单词的下标(最小下标)。
如果 searchWord 不是任何单词的前缀,则返回 -1 。
字符串 S 的 「前缀」是 S 的任何前导连续子字符串。
1 <= sentence.length <= 100
1 <= searchWord.length <= 10
sentence 由小写英文字母和空格组成。
searchWord 由小写英文字母组成。
前缀就是紧密附着于词根的语素,中间不能插入其它成分,并且它的位置是固定的——-位于词根之前。(引用自 前缀_百度百科 )
sentence = “i love eating burger”, searchWord = “burg”
4
“burg” 是 “burger” 的前缀,而 “burger” 是句子中第 4 个单词。
sentence = “this problem is an easy problem”, searchWord = “pro”
2
“pro” 是 “problem” 的前缀,而 “problem” 是句子中第 2 个也是第 6 个单词,但是应该返回最小下标 2 。
sentence = “i am tired”, searchWord = “you”
0
class Solution:
def isPrefixOfWord(self, sentence: str, searchWord: str) -> int:
a = sentence.split()
res = -1
for j, w in enumerate(a):
if len(w) < len(searchWord):
# 长度小于搜索字符串, 直接不满足要求
continue
for i in range(len(searchWord)):
if w[i] != searchWord[i]:
# 某一位不匹配了, 直接break
break
else:
# 都匹配, 就是要求的结果
# 注意要求的下标是从1开始的
return j + 1
return res
class Solution {
public:
int isPrefixOfWord(string sentence, string searchWord) {
auto split = [](const string& s, const char delim = ' ') {
vector<string> res;
istringstream stream(s);
string substr;
while(getline(stream, substr, delim)) {
res.emplace_back(substr);
}
return res;
};
auto words = split(sentence);
auto searchSize = searchWord.size();
for (int i = 0; i < words.size(); ++i) {
if (words[i].size() >= searchSize && words[i].compare(0, searchSize, searchWord) == 0) {
return i + 1;
}
}
return -1;
}
};
题目难度: 中等
原题链接
给你字符串 s 和整数 k 。
请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。
英文中的 元音字母 为(a, e, i, o, u)。
s = “abciiidef”, k = 3
3
子字符串 “iii” 包含 3 个元音字母。
s = “aeiou”, k = 2
2
任意长度为 2 的子字符串都包含 2 个元音字母。
s = “leetcode”, k = 3
2
class Solution:
def maxVowels(self, s: str, k: int) -> int:
v = {'a', 'e', 'i', 'o', 'u'}
res = 0
vcnt = 0
for i in range(k):
if s[i] in v:
# 先初始化计算[0,k]窗口的元音字母个数
vcnt += 1
res = vcnt
for b in range(len(s)):
e = b + k
if e >= len(s):
break
if s[e] in v:
# 更新新的右边界的值
vcnt += 1
if s[b] in v:
# 去除旧的左边界的值
vcnt -= 1
res = max(res, vcnt)
return res
class Solution {
public:
int maxVowels(string s, int k) {
vector<int> isVowel(s.size(), 0);
unordered_set<char> d = {'a', 'e', 'i', 'o', 'u'};
for (int i = 0; i < s.size(); ++i) {
if (d.find(s[i]) != d.end()) {
isVowel[i] = 1;
}
}
if (s.size() <= k) {
return accumulate(isVowel.begin(), isVowel.end(), 0);
}
int num = accumulate(isVowel.begin(), isVowel.begin() + k, 0);
int res = num;
for (int i = k; i < s.size(); ++i) {
num += isVowel[i] - isVowel[i - k];
res = max(res, num);
}
return res;
}
};
题目难度: 中等
原题链接
给你一棵二叉树,每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的,当它满足:路径经过的所有节点值的排列中,存在一个回文序列。
请你返回从根到叶子节点的所有路径中 伪回文 路径的数目。
root = [2,3,1,3,1,null,1]
2
root = [2,1,1,1,3,null,null,null,null,null,1]
1
[9]
1
class Solution:
def pseudoPalindromicPaths(self, root: TreeNode) -> int:
self.res = 0
if not root:
return 0
# 把集合移入和移出操作提取出来, 简化代码
def changeset(oddsets, v):
if v in oddsets:
oddsets.remove(v)
else:
oddsets.add(v)
def dfs(node, oddsets):
if not node.left and not node.right:
# 叶子节点, 且奇数个数的元素数目不大于1就是满足条件的路径
if len(oddsets) <= 1:
self.res += 1
return
if node.left:
# 注意每次改变集合状态后, 在dfs遍历完要恢复成原始状态, 避免对后面的遍历产生影响, 下同
changeset(oddsets, node.left.val)
dfs(node.left, oddsets)
changeset(oddsets, node.left.val)
if node.right:
changeset(oddsets, node.right.val)
dfs(node.right, oddsets)
changeset(oddsets, node.right.val)
dfs(root, {root.val})
return self.res
class Solution {
public:
int pseudoPalindromicPaths (TreeNode* root) {
int res = 0;
unordered_set<int> oddsets;
auto changeset = [&oddsets](int val) {
if (oddsets.find(val) == oddsets.end()) {
oddsets.insert(val);
} else {
oddsets.erase(val);
}
};
function<void(TreeNode*)> dfs = [&](TreeNode* root) {
if (!root) {
return;
}
changeset(root->val);
if (root->left || root->right) {
dfs(root->left);
dfs(root->right);
} else {
if (oddsets.size() <= 1) {
++res;
}
}
changeset(root->val);
};
dfs(root);
return res;
}
};
class Solution:
def pseudoPalindromicPaths(self, root: TreeNode) -> int:
self.res = 0
if not root:
return 0
def get1bit(n):
# 计算一个数字1的位数
res = 0
while n:
n &= n - 1
res += 1
return res
def dfs(node, mask):
if not node.left and not node.right:
# 叶子节点, 且奇数个数的元素数目不大于1就是满足条件的路径
if get1bit(mask) <= 1:
self.res += 1
return
if node.left:
dfs(node.left, mask ^ (1 << node.left.val))
if node.right:
dfs(node.right, mask ^ (1 << node.right.val))
dfs(root, 1 << root.val)
return self.res
class Solution {
public:
int pseudoPalindromicPaths (TreeNode* root) {
int res = 0;
auto countBits = [](int value) {
int count = 0;
while (value) {
++count;
value &= value - 1;
}
return count;
};
function<void(TreeNode*, int)> countPath = [&](TreeNode* root, int mask) {
if (!root) {
return;
}
mask ^= 1 << (root->val);
if (root->left || root->right) {
countPath(root->left, mask);
countPath(root->right, mask);
} else if (countBits(mask) <= 1) {
++res;
}
};
countPath(root, 0);
return res;
}
};
题目难度: 困难
原题链接
给你两个数组 nums1 和 nums2 。
请你返回 nums1 和 nums2 中两个长度相同的 非空 子序列的最大点积。
数组的非空子序列是通过删除原数组中某些元素(可能一个也不删除)后剩余数字组成的序列,但不能改变数字间相对顺序。比方说,[2,3,5] 是 [1,2,3,4,5] 的一个子序列而 [1,5,3] 不是。
定义 a = [a1, a2,…, an] 和 b = [b1, b2,…, bn] 的点积为:
nums1 = [2,1,-2,5], nums2 = [3,0,-6]
18
从 nums1 中得到子序列 [2,-2] ,从 nums2 中得到子序列 [3,-6] 。
它们的点积为 (2*3 + (-2)*(-6)) = 18 。
nums1 = [3,-2], nums2 = [2,-6,7]
21
从 nums1 中得到子序列 [3] ,从 nums2 中得到子序列 [7] 。
它们的点积为 (3*7) = 21 。
nums1 = [-1,-1], nums2 = [1,1]
-1
dp[i,j] = max(nums1[i]*nums2[j], nums1[i]*nums2[j]+mx)
, mx 是 max(dp[ii,jj]) (ii, 可能为负数, 这时候就只用 i 和 j 自身的乘积了
class Solution:
def maxDotProduct(self, nums1: List[int], nums2: List[int]) -> int:
dp = collections.defaultdict(int)
n1, n2 = len(nums1), len(nums2)
res = -float('inf')
premx = [-float('inf')] * n2
curmx = [-float('inf')] * n2
for i in range(n1):
# 复制premx的值
premx = curmx[::]
for j in range(n2):
v = nums1[i] * nums2[j]
# dp转移公式, 注意考虑j-1<0和premx[j - 1] < 0的特殊情况
dp[i,
j] = v if j - 1 < 0 or premx[j - 1] < 0 else v + premx[j -
1]
res = max(res, dp[i, j])
# 更新curmx
curmx[j] = max(curmx[j], dp[i, j])
if j - 1 >= 0:
curmx[j] = max(curmx[j], curmx[j - 1])
return res
class Solution {
public:
int maxDotProduct(vector<int>& nums1, vector<int>& nums2) {
int res = INT_MIN;
int n1 = nums1.size();
int n2 = nums2.size();
vector<int> curmx(n2, INT_MIN);
for (int i = 0; i < n1; ++i) {
auto premx = curmx;
for (int j = 0; j < n2; ++j) {
int value = nums1[i] * nums2[j];
if (j > 0 && premx[j - 1] > 0) {
value += premx[j - 1];
}
res = max(res, value);
curmx[j] = max(curmx[j], value);
if (j > 0) {
curmx[j] = max(curmx[j], curmx[j - 1]);
}
}
}
return res;
}
};
大家可以在下面这些地方找到我~
我的知乎专栏
我的 CSDN
我的简书
我的 Leetcode
我的牛客网博客
我的公众号: 每日精选算法题, 欢迎大家扫码关注~