这是我参与11月更文挑战的第7天,活动详情查看2021最后一次更文挑战
链接
leetcode-cn.com/contest/wee… 周赛一共四道题,今天先带来前两道题的解析。
题目
2047. 句子中的有效单词数
简单模拟
解析
简单模拟的关键是安排好每个判断语句的顺序,使得用最短的判断逻辑涵盖所有需要判断的情况。往往最简洁的涵盖所有情况的判断语句出错的可能性最低。
在这道题中,首先将每个token分隔开,注意多个空格的情况(使用Python最方便的做法是使用.split()代替.split(' ')然后再判断空token);然后判断token尾是否有标点符号;然后遍历每个字符,如果出现数字或标点即跳出判断;然后使用一个变量判断是否出现连词符、以及连词符的位置是否合法。
代码
class Solution:
def countValidWords(self, sentence: str) -> int:
interpunctions = ['!', ',', '.']
numbers = [chr(ord('0') + i) for i in range(0, 10)]
letters = [chr(ord('a') + i) for i in range(0, 26)]
tokens = list(filter(lambda word: len(word) > 0, sentence.split(' ')))
count = 0
for token in tokens:
begin, end = 0, len(token)-1 if token[-1] not in interpunctions else len(token) - 2
isHyphenExist = False
isTokenValid = True
p = begin
while p <= end:
if token[p] in numbers or token[p] in interpunctions:
isTokenValid = False
break
elif token[p] == '-':
if isHyphenExist == True or p == begin or p == end or token[p-1] not in letters or token[p+1] not in letters:
isTokenValid = False
break
else:
isHyphenExist = True
p += 1
if isTokenValid:
count += 1
return count
正则
解析
正则的写法很简洁(不知道时间复杂度和O(n)相比怎么样),但是根据题目的要求编写正则耗时,而且很难debug
代码
转载自解法
class Solution:
def countValidWords(self, sentence: str) -> int:
res = 0
for word in sentence.split() :
if re.match("[a-z]*([a-z]-[a-z])?[a-z]*[!,.]?$", word) : res += 1
return res
2048. 下一个更大的数值平衡数
暴力枚举(打表)
解析
在周赛中,因为看到数值范围只到10^6,所以我想将符合情况的数字都列了出来。但是由于没考虑完全列漏了,所以罚时了不少时间。(由于1、22、333这六个数字混合的情况很难写,所以还特意写了个循环转一下数字)
代码
class Solution:
def __init__(self):
self.ansList = [1, 22, 122, 212, 221, 333, 1333, 3133, 3313, 3331, 4444, 14444, 41444, 44144, 44414, 44441, 55555, 155555, 515555, 551555, 555155, 555515, 555551, 22333, 23233, 23323, 23332, 32233, 32323, 32332, 33223, 33232, 33322, 224444, 242444, 244244, 244424, 244442, 422444, 424244, 424424, 424442, 442244, 442424, 442442, 444224, 444242, 444422, 666666]
extras = [22333, 23233, 23323, 23332, 32233, 32323, 32332, 33223, 33232, 33322]
for i in range(0, 6):
for num in extras:
strList = list(str(num))
strList.insert(i, '1')
strNum = ''.join(strList)
self.ansList.append(int(strNum))
self.ansList.sort()
self.maxAns = 1224444
def nextBeautifulNumber(self, n: int) -> int:
for ans in self.ansList:
if n < ans:
return ans
return self.maxAns
改进
打表后的查找过程使用二分
回溯打表
解析
确定能组成数值平衡树的成分(比如1个1、2个2和3个3,2个2和4个4等),回溯出所有的数值平衡树然后二分查找
代码
class Solution {
public int nextBeautifulNumber(int n) {
Map<Integer,int[][]> map = new HashMap<>();
map.put(3,new int[][]{{1,2,2}});
map.put(4,new int[][]{{1,3,3,3}});
map.put(5,new int[][]{{1,4,4,4,4},{2,2,3,3,3}});
map.put(6,new int[][]{{1,2,2,3,3,3},{1,5,5,5,5,5},{2,2,4,4,4,4}});
int[][] enr = {{1,1},{22,22},{333,122},{4444,1333},{55555,14444},{666666,122333},{7777777,1224444}};
int len = String.valueOf(n).length();
if(len == 7) return enr[len-1][1];
if(n >= enr[len-1][0]) return enr[len][1];
if(n == 0) return 1;
if(n < 100) return 22;
PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int[] arr : map.get(len)){
backtrack(pq,arr,new boolean[arr.length],0,0,len,n,0);
}
return pq.isEmpty() ? enr[len-1][0] : pq.poll();
}
private void backtrack(PriorityQueue<Integer> pq,int[] arr,boolean[] flag,int num,int cont,int len ,int n ,int j){
if(cont == len && num > n){
pq.add(num);
}else{
for(int i=0; i<arr.length; i++){
if(flag[i]) continue;
num = num*10 + arr[i];
cont++;
flag[i] = true;
backtrack(pq,arr,flag,num,cont,len,n,j);
num = num/10;
cont--;
flag[i] = false;
}
}
}
}
暴力查找
解析
每次+1往上枚举,看+1的结果是否符合数值平衡数的要求。
代码
func nextBeautifulNumber(n int) int {
next:
for n++; ; n++ {
cnt := [10]int{}
for x := n; x > 0; x /= 10 {
cnt[x%10]++
}
for x := n; x > 0; x /= 10 {
if cnt[x%10] != x%10 {
continue next
}
}
return n
}
}
改进
在上述判断基础上判断0、7、8、9数字的出现,出现即跳出循环