LeetCode第140场周赛(Weekly Contest 140)解题报告

上一周的第139周赛由于时间冲突没有参加,这次就参加了第140周赛。

这周的周赛题主要是暴力,做题主要先实现,具体是不是最优的先不管,要优化都是赛后的事情了。

因为开始学习新的语言Java,因此最近的每日做题(可看我主页的置顶帖)和周赛几乎都优先用Java语言来做,有一些题还是用了最习惯的C++来做。

像第一道题,字符串分割题,之前用C++做是比较麻烦了,但Java和Python之类的有 split() 函数使用,所以方便了不少。语言是工具,哪个方便用哪个。


1. Bigram 分词(Occurrences After Bigram)

        AC代码(Java)

2. 活字印刷(Letter Tile Possibilities)

        AC代码(Java)

3.根到叶路径上的不足节点(Insufficient Nodes in Root to Leaf Paths)

        AC代码(Java)

4.不同字符的最小子序列(Smallest Subsequence of Distinct Characters)

        AC代码(C++)


LeetCode第140场周赛地址:

https://leetcode-cn.com/contest/weekly-contest-140/


1. Bigram 分词(Occurrences After Bigram)

题目链接

https://leetcode-cn.com/contest/weekly-contest-140/problems/occurrences-after-bigram/

题意

给出第一个词 first 和第二个词 second,考虑在某些文本 text 中可能以 "first second third" 形式出现的情况,其中 second 紧随 first 出现,third 紧随 second 出现。

对于每种这样的情况,将第三个词 "third" 添加到答案中,并返回答案。

示例 1:

输入:text = "alice is a good girl she is a good student", first = "a", second = "good"
输出:["girl","student"]

示例 2:

输入:text = "we will we will rock you", first = "we", second = "will"
输出:["we","rock"]

提示:

  1. 1 <= text.length <= 1000
  2. text 由一些用空格分隔的单词组成,每个单词都由小写英文字母组成
  3. 1 <= first.length, second.length <= 10
  4. first 和 second 由小写英文字母组成

解题思路

题目意思很直接,就是给定一个字符串文本 text,给定两个字符串单词,找出文本中跟着这两个单词后的第三个单词(可能有多个)。

这道题的难点主要就是将字符串文本text 进行分割,分割成多个字符串单词,然后进行匹配,如果按顺序匹配上了,那按顺序下去的第三个就是答案(可能会有多个)。

字符串分割可以使用到 split() 函数,根据题目,字符串只用空格分割,所以分割依据就是根据空格进行分割。得到一个字符串数组。

然后遍历这个数组,判断该位置 i 和下一个位置 i+1 是不是和给定的 first和 second相等,相等的话,则将 i+2 位置上的字符串保存下来。不相等,则遍历下一个 i 。

其中代码中用到了 ArrayList 这个相当于C++中的 vector

AC代码(Java)

class Solution {
    public String[] findOcurrences(String text, String first, String second) {
        String[] words = text.split(" ");
		int res = 0;
		ArrayList<String> ans = new ArrayList<String>();
		
		for(int i = 0;i < words.length-2;++i)
		{
			if(words[i].equals(first) && words[i+1].equals(second))
			{
				ans.add(words[i+2]);
			}
		}
		
        return ans.toArray(new String[ans.size()]) ;
    }
}

 


2. 活字印刷(Letter Tile Possibilities)

题目链接

https://leetcode-cn.com/contest/weekly-contest-140/problems/letter-tile-possibilities/ 

题意

你有一套活字字模 tiles,其中每个字模上都刻有一个字母 tiles[i]。返回你可以印出的非空字母序列的数目。

示例 1:

输入:"AAB"
输出:8
解释:可能的序列为 "A", "B", "AA", "AB", "BA", "AAB", "ABA", "BAA"。

示例 2:

输入:"AAABBC"
输出:188

提示:

  1. 1 <= tiles.length <= 7
  2. tiles 由大写英文字母组成

解题思路

根据题目与提示,字符串的总长度最多为7,所以可以利用DFS来枚举出所有组合的情况,然后统计不同的数量进行输出。

前提知识

在看这道题前,先要知道如何输出所有组合和全排列

可以参考我的另一篇博客:求一个数组里的数的所有组合和全排列(Java)

所以回到本题中,是第二种情况,我们先将字符串的变成一个整型数组,因为本题是要求求数量有多少个,所以把输出那部分变成一个计数,同时DFS函数的返回值就是目前有几个数,最后将这些数加起来进行输出即可。

 

AC代码(Java)

class Solution {
    public static int DFS(List<Integer> candidate, String prefix, HashSet<String> hs){
		int res = 0;
		if(prefix.length()!=0 && !hs.contains(prefix)){
			hs.add(prefix);
			res++;
		}

		for(int i=0; i<candidate.size(); i++){
			
			List<Integer> temp = new LinkedList<Integer>(candidate);
			int item = (int)temp.remove(i);  // 删除表示这个用过了
			res += DFS(temp, prefix+item, hs);
		}
		return res;
	}
    
    public int numTilePossibilities(String tiles) {
        Integer[] array = new Integer[tiles.length()];
		for(int i = 0;i < tiles.length();++i)
		{
			array[i] = tiles.charAt(i) - '0';
		}
		int res = 0;
		List<Integer> list = Arrays.asList(array);
		HashSet<String> hs = new HashSet<String>();
		res += DFS(list, "", hs);
		return res;
    }
}

 


3.根到叶路径上的不足节点(Insufficient Nodes in Root to Leaf Paths)

题目链接

https://leetcode-cn.com/contest/weekly-contest-140/problems/insufficient-nodes-in-root-to-leaf-paths/

题意

给定一棵二叉树的根 root,请你考虑它所有 从根到叶的路径:从根到任何叶的路径。(所谓一个叶子节点,就是一个没有子节点的节点)

假如通过节点 node 的每种可能的 “根-叶” 路径上值的总和全都小于给定的 limit,则该节点被称之为「不足节点」,需要被删除。

请你删除所有不足节点,并返回生成的二叉树的根。

提示:

  1. 给定的树有 1 到 5000 个节点
  2. -10^5 <= node.val <= 10^5
  3. -10^9 <= limit <= 10^9

解题分析

利用树的前序搜索,从根节点出发,一直求到最后叶节点,然后判断。

如果是叶节点了,即左右两边为 null,此时我们将 limit 一直减去节点的值,这样子在最后叶节点的时候,如果叶节点此时的 limit小于0,说明这个叶节点是要去掉的。

如果不是叶节点,那么就继续递归走下去,即从左右两下继续下去,此时要注意,本来这个节点还是有至少一个叶节点的,但是如果最后判断,叶节点都没有了,说明叶节点都不够,那么这个根节点就是「不足节点」需要被删掉的。

判断最后都没有返回,那就说明这个节点是有效的,直接返回原本的节点即可。

 

AC代码(Java)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode sufficientSubset(TreeNode root, int limit) {
        if (root == null) return null;
        limit -= root.val;
        if (root.left == null && root.right == null) {
            if (limit > 0) 
                return null;
            else
                return root;
        } 
        else 
        {
            // 本来是还有节点的,但是经过节点判断后,节点失效,所以这个也会被删掉,如例子3。
            if (root.left != null) 
                root.left = sufficientSubset(root.left, limit);
            if (root.right != null) 
                root.right = sufficientSubset(root.right, limit);
            
            if (root.left == null && root.right == null) 
                return null;
        }
        
        return root;
    }
}

 


4.不同字符的最小子序列(Smallest Subsequence of Distinct Characters)

题目链接

https://leetcode-cn.com/contest/weekly-contest-140/problems/smallest-subsequence-of-distinct-characters/

题意

返回字符串 text 中按字典序排列最小的子序列,该子序列包含 text 中所有不同字符一次。

示例 1:

输入:"cdadabcc"
输出:"adbc"

示例 2:

输入:"abcd"
输出:"abcd"

提示:

  1. 1 <= text.length <= 1000
  2. text 由小写英文字母组成

解题分析

利用贪心的方法,使用C++中的stack。

计算每一个字母在字符串中的最后位置,同时一个数组 vis 记录这个字母是否已经在栈中。然后从头遍历字符串。

然后分为以下几个情况

1、此时栈是空的,直接放进

2、栈不空,但这个字母已经放过了(不能重复),所以跳过

3、栈不空,而且这个字母没在里面。分为两个情况:①该字母比栈顶的元素大,直接放进。②字母比栈顶的元素小,判断栈顶是不是最后一个,如果不是最后一个,就取出,依次循环,直到栈顶的元素是最后一个为止。

所以总结上面:

1、字母已经放过了,那就跳过

2、栈不空,同时栈顶元素大过此时字母,同时栈顶元素不是最后一个,那就是第四点的②

3、其他:直接放进

 

AC代码(C++)

class Solution {
public:
    string smallestSubsequence(string text) {
        vector<int> last(26,0);
        vector<int> vis(26,0);
        stack<int> ans;

        for(int i=0;i<text.size();i++)
        {
            int e=text[i]-'a';
            if(last[e]<i) last[e]=i;   // 存储该字母的最后位置。
        }
        for(int i=0;i<text.size();i++)
        {
            int e=text[i]-'a';
            if(vis[e]) continue;   // 已经在里面了,跳过
            while(!ans.empty()&&last[ans.top()]>i&&e<=ans.top())
            {                                                       
                vis[ans.top()]=0;
                ans.pop();
            }
            if(!vis[e]){vis[e]=1;ans.push(e);}  // 其他情况,放进去后,就把该字母标记为放过
        }
        string res = "";
        while(!ans.empty())
        {
            char r = ans.top()+'a';
            res = r+res;
            ans.pop();
        }
        return res;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值