385. 迷你语法分析器
2022.4.15 每日一题
题目描述
给定一个字符串 s 表示一个整数嵌套列表,实现一个解析它的语法分析器并返回解析的结果 NestedInteger 。
列表中的每个元素只可能是整数或整数嵌套列表
示例 1:
输入:s = “324”,
输出:324
解释:你应该返回一个 NestedInteger 对象,其中只包含整数值 324。
示例 2:
输入:s = “[123,[456,[789]]]”,
输出:[123,[456,[789]]]
解释:返回一个 NestedInteger 对象包含一个有两个元素的嵌套列表:
1 一个 integer 包含值 123
2 一个包含两个元素的嵌套列表:
i. 一个 integer 包含值 456
ii. 一个包含一个元素的嵌套列表
a. 一个 integer 包含值 789
提示:
1 <= s.length <= 5 * 10^4
s 由数字、方括号 “[]”、负号 ‘-’ 、逗号 ','组成
用例保证 s 是可解析的 NestedInteger
输入中的所有值的范围是 [-106, 106]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/mini-parser
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
有点奇怪的一道题
首先这个字符串可以是一个数字,或者是一个列表
这两种处理方式还不同,所以如果刚开始是数字的话,需要特殊处理
然后就和那种常规的括号嵌套题一样了
需要认真理解所给定的这个数据结构,其实就是刚刚说的两种形式,一种可以直接存放一个数字,另一种就是存放多个数字,也就是题目所说的列表;而且存放列表的时候,不需要去创建一个list存放,而是直接加入add就行了,其实和list差不多
那么自然而然想到栈,开始做的时候,栈里面存放的是字符串,我想的是遇到左括号,创建新的NestedInteger 对象,遇到右括号弹出数字放到这个对象中,然后返回到原来的父对象,这样就可以完成这个处理了
但是遇到了两个问题,首先就是最初的父对象的创建,因为需要一个临时变量充当父对象,如果遇到左括号创建新的对象,那么外面必须本来就有一层对象,这样就会导致多创建一层,输出表现上就是外面多一层括号;也想了很多办法去处理,比如第一次遍历不创建新的对象,但是一直报错,不知道为什么
第二个问题就是遍历得到的顺序,因为是弹出来后放入的,所以顺序会反过来
代码如下:
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* public interface NestedInteger {
* // Constructor initializes an empty nested list.
* public NestedInteger();
*
* // Constructor initializes a single integer.
* public NestedInteger(int value);
*
* // @return true if this NestedInteger holds a single integer, rather than a nested list.
* public boolean isInteger();
*
* // @return the single integer that this NestedInteger holds, if it holds a single integer
* // Return null if this NestedInteger holds a nested list
* public Integer getInteger();
*
* // Set this NestedInteger to hold a single integer.
* public void setInteger(int value);
*
* // Set this NestedInteger to hold a nested list and adds a nested integer to it.
* public void add(NestedInteger ni);
*
* // @return the nested list that this NestedInteger holds, if it holds a nested list
* // Return empty list if this NestedInteger holds a single integer
* public List<NestedInteger> getList();
* }
*/
class Solution {
public NestedInteger deserialize(String s) {
//说实话,没太看懂到底该怎么表示这个结果
//但是单纯看这个题的话,应该就是用栈
NestedInteger res = new NestedInteger();
if(s.charAt(0) != '['){
res.setInteger(Integer.parseInt(s));
return res;
}
//用于记录上一层的列表
Map<NestedInteger, NestedInteger> map = new HashMap<>();
//map.put(res, new NestedInteger(Integer.MAX_VALUE));
Stack<String> stack = new Stack();
int l = s.length();
for(int i = l - 1; i >= 0; i--){
char c = s.charAt(i);
if(c == ',')
continue;
else if(c == ']'){
stack.push("]");
NestedInteger temp = new NestedInteger();
map.put(temp, res);
res.add(temp);
res = temp;
}else if(c == '['){
List<NestedInteger> list = new ArrayList<>();
while(!stack.isEmpty() && !stack.peek().equals("]")){
String p = stack.pop();
int t = Integer.parseInt(p);
NestedInteger tt = new NestedInteger(t);
res.add(tt);
}
//for(int j = list.size() - 1; j >= 0; j--)
// res.add(list.get(j));
stack.pop();
res = map.get(res);
//如果是数字
}else{
int flag = 1;
if(c == '-')
flag = -1;
int end = i - 1;
//System.out.println(i);
c = s.charAt(end);
while(end >= 0 && (Character.isDigit(c) || c == '-')){
end--;
c = s.charAt(end);
}
String ss = s.substring(end + 1, i + 1);
stack.push(ss);
i = end + 1;
//System.out.println(ss);
}
}
while(map.containsKey(res)){
//NestedInteger temp = map.get(res);
//System.out.println(map.get(temp).getInteger());
//if(map.get(temp).isInteger() && map.get(temp).getInteger() != Integer.MAX_VALUE)
res = map.get(res);
}
return res;
}
}
然后看了下题解是怎么写的,发现题解直接将这个对象存入了stack中,如果遇到数字就直接放在最近的对象中,遇到左括号创建新对象,遇到右括号弹出,我怎么就没想到呢。。。
主要关键点还是栈里存放的是这种对象
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* public interface NestedInteger {
* // Constructor initializes an empty nested list.
* public NestedInteger();
*
* // Constructor initializes a single integer.
* public NestedInteger(int value);
*
* // @return true if this NestedInteger holds a single integer, rather than a nested list.
* public boolean isInteger();
*
* // @return the single integer that this NestedInteger holds, if it holds a single integer
* // Return null if this NestedInteger holds a nested list
* public Integer getInteger();
*
* // Set this NestedInteger to hold a single integer.
* public void setInteger(int value);
*
* // Set this NestedInteger to hold a nested list and adds a nested integer to it.
* public void add(NestedInteger ni);
*
* // @return the nested list that this NestedInteger holds, if it holds a nested list
* // Return empty list if this NestedInteger holds a single integer
* public List<NestedInteger> getList();
* }
*/
class Solution {
public NestedInteger deserialize(String s) {
//说实话,没太看懂到底该怎么表示这个结果
//但是单纯看这个题的话,应该就是用栈
NestedInteger res = new NestedInteger();
if(s.charAt(0) != '['){
res.setInteger(Integer.parseInt(s));
return res;
}
Stack<NestedInteger> stack = new Stack();
int l = s.length();
int num = 0;
int flag = 1;
for(int i = 0; i < l; i++){
char c = s.charAt(i);
//如果遇到逗号或者右括号,先放入数字
if(c == ',' || c == ']'){
//如果上一位是数字的话,放入该数字
if(Character.isDigit(s.charAt(i - 1))){
NestedInteger top = stack.peek();
top.add(new NestedInteger(flag * num));
}
num = 0;
flag = 1;
//如果是右括号,说明上一层处理完了,放入上一层
if(c == ']' && stack.size() > 1){
NestedInteger top = stack.pop();
stack.peek().add(top);
}
//如果是左括号,创建新的对象
}else if(c == '['){
NestedInteger t = new NestedInteger();
stack.push(t);
}else if(c == '-'){
flag = -1;
}else{
num = num * 10 + c - '0';
}
}
return stack.pop();
}
}
class Solution:
def deserialize(self, s: str) -> NestedInteger:
if s[0] != '[':
return NestedInteger(int(s))
stack, num, negative = [], 0, False
for i, c in enumerate(s):
if c == '-':
negative = True
elif c.isdigit():
num = num * 10 + int(c)
elif c == '[':
stack.append(NestedInteger())
elif c in ',]':
if s[i-1].isdigit():
if negative:
num = -num
stack[-1].add(NestedInteger(num))
num, negative = 0, False
if c == ']' and len(stack) > 1:
stack[-2].add(stack.pop())
return stack.pop()
479. 最大回文数乘积
2022.4.16 每日一题
题目描述
给定一个整数 n ,返回 可表示为两个 n 位整数乘积的 最大回文整数 。因为答案可能非常大,所以返回它对 1337 取余 。
示例 1:
输入:n = 2
输出:987
解释:99 x 91 = 9009, 9009 % 1337 = 987
示例 2:
输入: n = 1
输出: 9
提示:
1 <= n <= 8
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/largest-palindrome-product
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
题解给的竟然是暴力。
建议参考烟花大佬的题解:https://leetcode-cn.com/problems/largest-palindrome-product/solution/mei-ju-shu-xue-by-megurine-p1bn/
在一定程度上,用数学公式给了更简介有依据的方法
class Solution {
public int largestPalindrome(int n) {
//想想这样的整数有什么特点吗
//首先范围是 10^(n - 1) * 10^(n -1) ~ (10^n) - 1 * 10^n - 1
//又是一个数学问题
//肯定不能一一列举,想想怎么弄
//在这个范围内,从大到小,例如最大是99*99=9801,那么如果9打头还要想是回文,必须是末尾也是9
//只有1*9,3*3是9,所以考虑91*99,93*93
//同样,对于8开头,末尾是8,就考虑2*4,1*8
//考虑的复杂了,竟然真的是枚举....
if(n == 1)
return 9;
int res = 0;
int left = (int)(Math.pow(10, n) - 1);
for(int i = left; res == 0; i--){
//先构造右半部分
long num = i;
int j = i;
while(j > 0){
num = num * 10 + j % 10;
j /= 10;
}
//构造完以后判断能不能被整除
long x = left;
while(x * x >= num){
if(num % x == 0){
res = (int)(num % 1337);
return res;
}
x--;
}
}
return 0;
}
}
range第一第二个参数限定的是范围
class Solution:
def largestPalindrome(self, n: int) -> int:
if n == 1:
return 9
max = 10 ** n - 1
for i in range(max, max // 10, -1):
num = i
j = i
while j:
num = num * 10 + j % 10
j //= 10
x = max
while x * x >= num:
if num % x == 0:
return num % 1337
x -= 1
819. 最常见的单词
2022.4.17 每日一题
题目描述
给定一个段落 (paragraph) 和一个禁用单词列表 (banned)。返回出现次数最多,同时不在禁用列表中的单词。
题目保证至少有一个词不在禁用列表中,而且答案唯一。
禁用列表中的单词用小写字母表示,不含标点符号。段落中的单词不区分大小写。答案都是小写字母。
示例:
输入:
paragraph = “Bob hit a ball, the hit BALL flew far after it was hit.”
banned = [“hit”]
输出: “ball”
解释:
“hit” 出现了3次,但它是一个禁用的单词。
“ball” 出现了2次 (同时没有其他单词出现2次),所以它是段落里出现次数最多的,且不在禁用列表中的单词。
注意,所有这些单词在段落里不区分大小写,标点符号需要忽略(即使是紧挨着单词也忽略, 比如 “ball,”),
"hit"不是最终的答案,虽然它出现次数更多,但它在禁用单词列表中。
提示:
1 <= 段落长度 <= 1000
0 <= 禁用单词个数 <= 100
1 <= 禁用单词长度 <= 10
答案是唯一的, 且都是小写字母 (即使在 paragraph 里是大写的,即使是一些特定的名词,答案都是小写的。)
paragraph 只包含字母、空格和下列标点符号!?’,;.
不存在没有连字符或者带有连字符的单词。
单词里只包含字母,不会出现省略号或者其他标点符号。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/most-common-word
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
模拟,不过细节不少
class Solution {
public String mostCommonWord(String paragraph, String[] banned) {
Map<String, Integer> map = new HashMap<>();
Set<String> set = new HashSet<>();
for(String s : banned)
set.add(s);
int l = paragraph.length();
StringBuffer sb = new StringBuffer();
for(int i = 0; i < l; i++){
char c = paragraph.charAt(i);
if(!Character.isLetter(c)){
if(sb.length() == 0)
continue;
String temp = sb.toString();
sb = new StringBuffer();
//System.out.println(temp);
if(set.contains(temp))
continue;
//System.out.println(temp);
map.put(temp, map.getOrDefault(temp, 0) + 1);
continue;
}
if(Character.isUpperCase(c)){
c = (char)(c + 32);
//System.out.println(c);
}
sb.append(c);
if(i == l - 1){
String temp = sb.toString();
if(set.contains(temp))
continue;
map.put(temp, map.getOrDefault(temp, 0) + 1);
}
}
int max = 0;
String res = "";
for(String s : map.keySet()){
if(map.get(s) > max){
max = map.get(s);
res = s;
}
}
return res;
}
}
哈希表对应这里的Counter
统计哈希表中最大数量的单词 max(counter.values())
一行的那种python代码就先不看了
class Solution:
def mostCommonWord(self, paragraph: str, banned: List[str]) -> str:
ban = set(banned)
count = Counter()
word, n = "", len(paragraph)
for i in range(n + 1):
if i < n and paragraph[i].isalpha():
word += paragraph[i].lower()
elif word:
if word not in ban:
count[word] += 1
word = ""
maxc = max(count.values())
for w in count:
if count[w] == maxc:
return w