最近一段时间事情好多,好久没有打周赛辽。(我不会承认因为我懒)
趁着思路还热乎,来写一发题解
检查单词是否为句中其他单词的前缀
这个题目用java的字符串来处理还是比较容易的,先用split
方法将文章按空格拆开,得到单词数组。
由于题目询问的是文章中的单词是否包含指定字符串的前缀。
因此对于每个单词:
- 先判断它的长度够不够包含指定字符串。
- 如果足够长,则取前面一段与指定字符串做比较,相等了就是包含这个指定字符串,返回这个单词的下标+1即可。
- 最后不要忘记在整个循环结束后加上无答案的结果的
-1
.
public class Solution1 {
public int isPrefixOfWord(String sentence, String searchWord) {
if(sentence.length() == 0)
{
return -1;
}
String[] words = sentence.split(" ");
for(int i = 0;i < words.length;i++)
{
if(words[i].length() >= searchWord.length())
{
if(words[i].substring(0,searchWord.length()).equals(searchWord))
{
return i + 1;
}
}
}
return -1;
}
}
定长子串中元音的最大数目
这个题要求统计字符串中每个定长字串中的元音,并输出其中包含元音的最大数目。
首先,这个题目最朴素的思想是暴力统计每一个字串中元音的数量。但是掐指一算,这个复杂度是O(nm),考虑到数据规模是10^5,这个复杂度有些吃不消,妥妥的TLE。
我们可以对刚刚的算法进行进一步的思考。不难发现起始位置相差为1的两个字串存在大量内容重叠,仅有前后两个字符不一样。
因此我们可以通过一个滑动窗口来解决这个问题。这个窗口每向前走一步,就统计新加入的单词是否为元音,并抛弃最末尾的单词,抛弃的时候记得修正序列中元音的个数。
public class Solution2 {
//判断元音的方法
private boolean isVowel(char ch)
{
switch(ch)
{
case 'a':return true;
case 'e':return true;
case 'i':return true;
case 'o':return true;
case 'u':return true;
default :return false;
}
}
public int maxVowels(String s, int k) {
char[] string = s.toCharArray();
int cnt = 0;
int ans = 0;
//预处理窗口
for(int i = 0;i < k - 1;i++)
{
if(isVowel(string[i]))
{
cnt++;
}
}
for(int i = k - 1;i < string.length;i++)
{
if(isVowel(string[i]))//加入新元素
{
cnt++;
}
ans = Math.max(ans, cnt);//答案
if(isVowel(string[i - k]))//删除末尾元素
{
cnt--;
}
}
return ans;
}
}
二叉树中的伪回文路径
这是个考察递归遍历二叉树以及回文串性质的题目。对于这个题目,有两点是值得注意的:
- 利用递归遍历从根到叶子的路径,并统计期间路过节点的值出现的次数,在叶子节点统计答案。
- 一些字符可以排列成一个回文串,当且仅当其中出现次数为奇数的字符数量不超过一个。
对于第一点,统计次数,由于题目中将节点的值限制在1-9,因此可以直接采用数组进行统计。
如果没有这个限制,可能就需要使用到map或者其他的数据结构来处理这个问题。
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
public class Solution3 {
static int ans = 0; //答案
private boolean charge(int[] cnt) //判断是否可以形成回文序列
{
boolean flag = false;
for(int i = 1;i <= 9;i++)
{
if(cnt[i] % 2 == 1)
{
if(flag)
{
return false;
}
flag = true;
}
}
return true;
}
private void dfs(TreeNode root,int[] cnt)
{
cnt[root.val] ++; //统计该节点的值
if(root.left == null && root.right == null)//叶子节点,统计答案
{
if(charge(cnt))
{
ans++;
}
}
if(root.left != null)
{
dfs(root.left,cnt);
}
if(root.right != null)
{
dfs(root.right,cnt);
}
cnt[root.val] --;//回溯时一定要删去该层的统计
}
public int pseudoPalindromicPaths (TreeNode root) {
int[] cnt = new int[10];
dfs(root,cnt);
return ans;
}
}
两个子序列的最大点积
”一般来说,最后一题,都是个dp——沃茨基硕德”
这个题目也不例外 (好像大多数子序列的题都是dp)
思路嘛。。。可能会有些绕,但是不难理解,但请原谅我的语文不好,有口难辩QAQ。就先把通过的代码放在这里吧。(我尽量在注释中阐明我的想法。)
public class Solution4 {
public int maxDotProduct(int[] nums1, int[] nums2) {
int[] dp = new int[nums2.length];
for(int i = 0;i < nums2.length;i++)//初始化dp数组
{
dp[i] = 1 << 31;
}
for(int i = 0,max;i < nums1.length;i++)//遍历数组1
{
max = 1 << 31; //挑选前项的最大值
for(int j = 0,temp;j < nums2.length;j++)//遍历数组2
{
//dp[j]表示对于nums1的前i位以及nums2数组前j位元素中最大的点积值
//如果取nums1中第i位元素与nums2中第j位元素的点积,则该位值为前j-1项最大值(小于零取零)加上nums1[i]*nums2[j]。否则该位不变
temp = dp[j];
dp[j] = Math.max(temp,nums1[i] * nums2[j] + Math.max(0, max));
max = max > temp ? max : temp; //统计前j-1为最大值
}
}
int ans = 1 << 31;
for(int num : dp)//统计答案
{
ans = ans > num ? ans : num;
}
return ans;
}
}