做出来了三题,最后一题python查询用O(n)的方法超时了,一直在想小于O(n)的方法,然后gg,不过别人用c++写的O(n)的方法也很巧妙,学习到了,另外python用collections.Counter就能过,估计这个库的优化很好吧。
给你一个按 YYYY-MM-DD 格式表示日期的字符串 date,请你计算并返回该日期是当年的第几天。
通常情况下,我们认为 1 月 1 日是每年的第 1 天,1 月 2 日是每年的第 2 天,依此类推。每个月的天数与现行公元纪年法(格里高利历)一致。
比较简单的一道题,你只要知道每个月份都有多少天,并且闰年的二月为29天(闰年为400的倍数 或者 4的倍数且不为100的倍数),当前日期的天数即为(MM - 1)个月的天数总和 + DD
class Solution:
def ordinalOfDate(self, date: str) -> int:
# 生成一个月份天数表,也可以自己手打一个
month_days = []
for i in range(12):
if i == 1:
month_days.append(28)
elif i % 2 == 0:
if i <= 6:
month_days.append(31)
else:
month_days.append(30)
elif i % 2 == 1:
if i <= 6:
month_days.append(30)
else:
month_days.append(31)
year = int(date[0:4])
month = int(date[5:7])
day = int(date[8:])
ans = 0
for i in range(1, month):
ans += month_days[i - 1]
if i == 2 and (year % 400 == 0 or (year % 4 == 0 and year % 100 != 0)):
ans += 1
ans += day
return ans
这里有 d 个一样的骰子,每个骰子上都有 f 个面,分别标号为 1, 2, …, f。
我们约定:掷骰子的得到总点数为各骰子面朝上的数字的总和。
如果需要掷出的总点数为 target,请你计算出有多少种不同的组合情况(所有的组合情况总共有 f^d 种),模 10^9 + 7 后返回。
动态规划,用ans[i][j]表示用了i颗骰子,掷出j的组合情况总数。
ans[0][0] = 1,
ans[i][j] = ans[i-1][j-1] + ans[i-1][j-2] + … + ans[i -1][j - f],
最后输出ans[d][target] 即可。
由于每一层只和上一层有关,可以稍加空间优化,ans[j] = ans[j - 1] + … + ans[j - f],j的状态从大到小遍历即可,最后输出ans[target],记得除以模取余哦。
class Solution:
def numRollsToTarget(self, d: int, f: int, target: int) -> int:
ans = [0 for j in range(target + 1)]
ans[0] = 1
for i in range(d):
for j in range(target , -1, -1):
ans[j] = 0
for k in range(1, f + 1):
if j - k >= 0 and ans[j - k] != 0:
ans[j] = (ans[j] + ans[j - k]) % (10**9 + 7)
return ans[target]
如果字符串中的所有字符都相同,那么这个字符串是单字符重复的字符串。
给你一个字符串 text,你只能交换其中两个字符一次或者什么都不做,然后得到一些单字符重复的子串。返回其中最长的子串的长度。
这题题意很清楚,要么只能换一个字符,要么不换,故我们每次都记录三段,上上段一样的,上段一样的,以及当前一样的段。
若上上段的内容和当前段的内容一致,且上段的字符只有1个,那么我们可以把上段换掉,让上上段和当前段拼接起来,如果别的地方还有当前段的字符则可以用其它地方的字符去替换,如果没有,则只能用上上段最左侧或当前段最右侧来替换上段。
class Solution:
def maxRepOpt1(self, text: str) -> int:
alphabet_map = {'':0}
# 统计每个字符的最多数量
for each in text:
if each not in alphabet_map:
alphabet_map[each] = 1
else:
alphabet_map[each] += 1
# 上上段
last_last_alp = ''
last_last_sum = 0
# 上一段
last_alp = ''
last_sum = 0
# 当前段
now_alp = ''
now_sum = 0
ans = 0
for each in text:
if each == now_alp:
now_sum += 1
else:
if last_sum == 1 and now_alp == last_last_alp:
if alphabet_map[now_alp] > last_last_sum + now_sum:
ans = max(ans, last_last_sum + now_sum + 1)
else:
ans = max(ans, last_last_sum + now_sum)
else:
if alphabet_map[now_alp] > now_sum:
ans = max(ans, now_sum + 1)
else:
ans = max(ans, now_sum)
last_last_sum = last_sum
last_last_alp = last_alp
last_sum = now_sum
last_alp = now_alp
now_alp = each
now_sum = 1
# 结束后要把最后一段也统计一下
if last_sum == 1 and now_alp == last_last_alp:
if alphabet_map[now_alp] > last_last_sum + now_sum:
ans = max(ans, last_last_sum + now_sum + 1)
else:
ans = max(ans, last_last_sum + now_sum)
else:
if alphabet_map[now_alp] > now_sum:
ans = max(ans, now_sum + 1)
else:
ans = max(ans, now_sum)
return ans
实现一个 MajorityChecker 的类,它应该具有下述几个 API:
每次查询 query(…) 会返回在 arr[left], arr[left+1], …, arr[right] 中至少出现阀值次数 threshold 的元素,如果不存在这样的元素,就返回 -1。
一般的想法query就把范围内的数都统计一下,这样就需要辅助的空间,而且效率上可能相对比较慢。
因为题目给定了条件,threshold 一定比查询范围长度的一半要长,那么答案要么是不存在,要么只有一个答案。
那么我们可以考虑把查询范围分成两段ab,若a段中没有超过一半的数,b段中也没有超过一半的数,那么肯定是不存在了;
所以要使其可能,则在a段中没有超过一半,在b段中必须超过一半才有可能(有点像数学中的反证法)。
那么我们从头开始遍历,开始以第一个数为基准,搜到第n个数时,是基准的数量和不是基准的数量正好一半一半,满足了a段中没有超过一半的数,那么我们直接看b段就行了,把基准赋值为b段中的第一个数,直至遍历完。
我们最后得到的基准即为有可能成为超过一半的查询范围长度的数,而非查询范围中最多的数,这点需要注意。
c++代码
class MajorityChecker {
public:
vector<int> my_arr;
MajorityChecker(vector<int>& arr) {
my_arr = arr;
}
int query(int left, int right, int threshold) {
//确定可能能大于一半的number
int number = my_arr[left];
int count = 1;
for (int i = left + 1; i <= right; ++i)
{
if (my_arr[i] == number)
{
++count;
}
else if (count > 0)
{
--count;
}
else
{
count = 1;
number = my_arr[i];
}
}
// 计数
count = 0;
for (int i = left; i <= right; ++i)
if (my_arr[i] == number)
++count;
if (count >= threshold)
{
return number;
}
return -1;
}
};
python3代码
class MajorityChecker:
def __init__(self, arr: List[int]):
self.arr = arr
def query(self, left: int, right: int, threshold: int) -> int:
temp = self.arr[left:right+1]
dic = collections.Counter(temp)
for key, val in dic.items():
if val >= threshold:
return key
return -1