难度简单2
公司里共有 n
名员工,按从 0
到 n - 1
编号。每个员工 i
已经在公司工作了 hours[i]
小时。
公司要求每位员工工作 至少 target
小时。
给你一个下标从 0 开始、长度为 n
的非负整数数组 hours
和一个非负整数 target
。
请你用整数表示并返回工作至少 target
小时的员工数。
示例 1:
输入:hours = [0,1,2,3,4], target = 2
输出:3
解释:公司要求每位员工工作至少 2 小时。
- 员工 0 工作 0 小时,不满足要求。
- 员工 1 工作 1 小时,不满足要求。
- 员工 2 工作 2 小时,满足要求。
- 员工 3 工作 3 小时,满足要求。
- 员工 4 工作 4 小时,满足要求。
共有 3 位满足要求的员工。
示例 2:
输入:hours = [5,1,4,2,2], target = 6
输出:0
解释:公司要求每位员工工作至少 6 小时。
共有 0 位满足要求的员工。
提示:
1 <= n == hours.length <= 50
0 <= hours[i], target <= 105
class Solution {
public int numberOfEmployeesWhoMetTarget(int[] hours, int target) {
int ans = 0;
for(int h : hours){
if(h >= target)
ans += 1;
}
return ans;
}
}
class Solution:
def numberOfEmployeesWhoMetTarget(self, hours: List[int], target: int) -> int:
return sum(h >= target for h in hours)
难度中等4
给你一个由 正 整数组成的数组 nums
。
如果数组中的某个子数组满足下述条件,则称之为 完全子数组 :
返回数组中 完全子数组 的数目。
子数组 是数组中的一个连续非空序列。
示例 1:
输入:nums = [1,3,1,2,2]
输出:4
解释:完全子数组有:[1,3,1,2]、[1,3,1,2,2]、[3,1,2] 和 [3,1,2,2] 。
示例 2:
输入:nums = [5,5,5,5]
输出:10
解释:数组仅由整数 5 组成,所以任意子数组都满足完全子数组的条件。子数组的总数为 10 。
提示:
1 <= nums.length <= 1000
1 <= nums[i] <= 2000
双重循环:枚举左端点,寻找右端点
class Solution {
public int countCompleteSubarrays(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int num : nums)
set.add(num);
int cnt = set.size();
int ans = 0, n = nums.length;
for(int left = 0; left < n; left++){
int right = left;
set = new HashSet<>();
while(right < n && set.size() <= cnt){
set.add(nums[right++]);
if(set.size() == cnt)
ans += 1;
}
}
return ans;
}
}
当 窗口 [l, r]
内子数组满足 完全子数组
时,对于任意右侧边界 r <= i < n
,窗口 [l, i]
内子数组亦满足 完全子数组
,即对于当前窗口左侧边界 r
,存在 n - r
个 完全子数组
~
class Solution {
// 当右端点固定时,不断循环直到[left, right]不满足要求,此时合法左端点的个数就是left
public int countCompleteSubarrays(int[] nums) {
var set = new HashSet<Integer>();
for (int x : nums) set.add(x);
int m = set.size();
var cnt = new HashMap<Integer, Integer>();
int ans = 0, left = 0;
for (int v : nums) { // 枚举子数组右端点 v=nums[i]
cnt.merge(v, 1, Integer::sum);
while (cnt.size() == m) {
int x = nums[left++];
if (cnt.merge(x, -1, Integer::sum) == 0)
cnt.remove(x);
}
ans += left; // 子数组左端点 < left 的都是合法的
}
return ans;
}
}
两类滑窗的题目:
1、while循环结束后,不满足要求(while循环内是满足要求的) - 本题属于这种
2、while循环结束后,满足要求
难度中等9
给你三个字符串 a
,b
和 c
, 你的任务是找到长度 最短 的字符串,且这三个字符串都是它的 子字符串 。
如果有多个这样的字符串,请你返回 字典序最小 的一个。
请你返回满足题目要求的字符串。
注意:
a
和 b
,如果在第一个不相同的字符处,a
的字母在字母表中比 b
的字母 靠前 ,那么字符串 a
比字符串 b
字典序小 。示例 1:
输入:a = "abc", b = "bca", c = "aaa"
输出:"aaabca"
解释:字符串 "aaabca" 包含所有三个字符串:a = ans[2...4] ,b = ans[3..5] ,c = ans[0..2] 。结果字符串的长度至少为 6 ,且"aaabca" 是字典序最小的一个。
示例 2:
输入:a = "ab", b = "ba", c = "aba"
输出:"aba"
解释:字符串 "aba" 包含所有三个字符串:a = ans[0..1] ,b = ans[1..2] ,c = ans[0..2] 。由于 c 的长度为 3 ,结果字符串的长度至少为 3 。"aba" 是字典序最小的一个。
提示:
1 <= a.length, b.length, c.length <= 100
a
,b
,c
只包含小写英文字母。由于就三个字符串,只要枚举 3!
中排列就可以了
class Solution:
def minimumString(self, a: str, b: str, c: str) -> str:
def sadd(s1,s2):
if s1 in s2:
return s2
if s2 in s1:
return s1
for j in range(min(len(s1),len(s2)),0,-1):
if s1[len(s1)-j:]==s2[:j]:
return s1+s2[j:]
return s1+s2
return sorted([sadd(sadd(a,b),c),sadd(sadd(b,a),c),sadd(sadd(a,c),b),sadd(sadd(c,a),b),sadd(sadd(b,c),a),sadd(sadd(c,b),a)],key=lambda x:[len(x),x])[0]
难度困难8
给你两个正整数 low
和 high
,都用字符串表示,请你统计闭区间 [low, high]
内的 步进数字 数目。
如果一个整数相邻数位之间差的绝对值都 恰好 是 1
,那么这个数字被称为 步进数字 。
请你返回一个整数,表示闭区间 [low, high]
之间步进数字的数目。
由于答案可能很大,请你将它对 109 + 7
取余 后返回。
**注意:**步进数字不能有前导 0 。
示例 1:
输入:low = "1", high = "11"
输出:10
解释:区间 [1,11] 内的步进数字为 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 和 10 。总共有 10 个步进数字。所以输出为 10 。
示例 2:
输入:low = "90", high = "101"
输出:2
解释:区间 [90,101] 内的步进数字为 98 和 101 。总共有 2 个步进数字。所以输出为 2 。
提示:
1 <= int(low) <= int(high) < 10100
1 <= low.length, high.length <= 100
low
和 high
只包含数字。low
和 high
都不含前导 0 。mask表示前一个数位上是多少
判断条件:if(Math.abs(d - mask) == 1 || !isNum)
,表示 ①相邻数位之间差的绝对值都 恰好 是 1
或者 ②还不是数字(刚刚开始从0计数)
class Solution {
private static final int MOD = (int)1e9+7;
int dp[][]; // i, mask 记忆化搜索不需要记忆islimit和isnum
public int countSteppingNumbers(String low, String high) {
int m = low.toCharArray().length;
dp = new int[m][10];
for(int i = 0; i < m; i++) Arrays.fill(dp[i], -1);
char[] s1 = low.toCharArray();
s1[s1.length-1]--;
int lownum = f(0, 0, true, false, s1);
int n = high.toCharArray().length;
dp = new int[n][10];
for(int i = 0; i < n; i++) Arrays.fill(dp[i], -1);
int highnum = f(0, 0, true, false, high.toCharArray());
return (highnum - lownum + MOD) % MOD;
}
// mask表示前一个数位
public int f(int i, int mask, boolean isLimit, boolean isNum, char[] s){
if(i == s.length) //到了递归终点
return isNum ? 1 : 0;
if(!isLimit && isNum && dp[i][mask] >= 0)
return dp[i][mask];
int res = 0;
if(!isNum) res = f(i + 1, mask, false, false, s) % MOD;
// 枚举要填入的数字 d
for(int d = isNum ? 0 : 1, up = isLimit? s[i]-'0' : 9; d <= up; d++){
if(Math.abs(d - mask) == 1 || !isNum){ // d不在mask中【这里的判断具体看题目要求】
res = (res + f(i+1, d, isLimit & (d == up), true, s)) % MOD;
}
}
if(!isLimit && isNum) dp[i][mask] = res % MOD;
return res % MOD;
}
}