6112. 装满杯子需要的最短总时长
https://leetcode.cn/problems/minimum-amount-of-time-to-fill-cups/
思路:每次取最大的两个数,直到次大数为0,这样剩下的某种温度的水的杯子只能一次装一杯
class Solution {
public int fillCups(int[] amount) {
Arrays.sort(amount);
int ans=0;
while(amount[1]>0){
amount[1]--;
amount[2]--;
ans++;
Arrays.sort(amount);//排序 保证后两个数较大
}
ans+=amount[2];//剩下的温度的水需要装的次数
return ans;
}
}
6113. 无限集中的最小数字
https://leetcode.cn/problems/smallest-number-in-infinite-set/
思路:最简单的做法就是使用TreeSet, 直接利用有序集合的API。 这里我们使用数组模拟,nums[i]=0说明整数i不存在,否则nums[i]=i, 表示位置i上面存放整数i;
class SmallestInfiniteSet {
int[] nums;
int min;
public SmallestInfiniteSet() {
nums=new int[1001];
for(int i=1;i<=1000;i++){
nums[i]=i;//添加1000个元素
}
min=1;//初始化最小值为1
}
public int popSmallest() {
int re=min;
nums[re]=0;//表示删除
for(int i=min+1;i<=1000;i++){
if(nums[i]!=0){//找到min后面第一个存在与集合中的数
min=i;
break;
}
}
return re;
}
public void addBack(int num) {
if(nums[num]!=0){
return;
}
nums[num]=num;//加入集合
if(num<min){
min=num;
}
}
}
/**
* Your SmallestInfiniteSet object will be instantiated and called as such:
* SmallestInfiniteSet obj = new SmallestInfiniteSet();
* int param_1 = obj.popSmallest();
* obj.addBack(num);
*/
6114. 移动片段得到字符串
https://leetcode.cn/problems/move-pieces-to-obtain-a-string/
思路:首先判断去掉_字符后的start和target是否相同,如果不相同则不能通过移动得到; 然后遍历start, 当遇到L时,判断start对应的L和target中的L的相对位置,假设start[i]=L end[j]=L 如果j>i, 说明无法移动,假设start[i]=R end[j]=R 如果j<i, 说明无法移动
class Solution {
public boolean canChange(String start, String target) {
//去掉_后的start应该一样
if(!start.replaceAll("_","").equals(target.replaceAll("_",""))){
return false;
}
int i=0,j=0,n=start.length();
while(i<n&&j<n){
if(start.charAt(i)=='_'){//遇到start中的_ 跳过
i++;
continue;
}
//此时遇到start中的L或R
while(target.charAt(j)=='_'){
j++;//找到target中的非_字符
}
if(i!=j){//i==j就不需要移动了
if(start.charAt(i)=='L'){//start[i]=L end[j]=L
if(j>i){//j<--i i只能向左移动 如果j>i 无法完成移动
return false;
}
}else if(start.charAt(i)=='R'){//start[i]=R end[j]=R
if(j<i){//i-->J i只能向右移动 如果j<i 无法完成移动
return false;
}
}
}
i++;
j++;
}
return true;
}
}
6115. 统计理想数组的数目
https://leetcode.cn/problems/count-the-number-of-ideal-arrays/
分析:
假设一个理想数组中的最大值为num, 则数组中的元素个数最多为 l o g n u m + 1 log\small num+1 lognum+1 , 此时数组中的元素关系为: arr[i+1]=2*arr[i] 比如最大元素为8, 理想数组最长为1 2 4 8, 一共4个元素
记作f(i,j)
表示以数字i结尾的长度为j的理想数组的个数,则
f
(
i
,
j
)
=
∑
k
<
i
并
且
k
是
i
的
因
数
f
(
k
,
j
−
1
)
f(i,j)=\sum_{k<i并且k是i的因数}f(k,j-1)
f(i,j)=∑k<i并且k是i的因数f(k,j−1)
初始值f(i,1)=1
题目中允许在完美数组中出现相同的元素,假设完美数组中有t种元素,对这t中元素中每一种元素,只要确定了每种元素第一次出现的位置,则整个数组就确定了。
第一个位置肯定要作为某类元素第一次出现的位置(其他位置可以是某种元素第一次出现的位置也可以是重复元素的位置), 一共有n个位置,除了第一个位置,还有n-1个位置,现在还有t-1种元素,因此在n-1个位置中寻找t-1开始位置,每个位置都是某类元素的第一次出现的位置, 方案数: C n − 1 t − 1 C_{n-1}^{t-1} Cn−1t−1
所以总的方案数:
∑ i = 1 m a x V a l ∑ j = 1 l o g m a x V a l + 1 [ f ( i , j ) ∗ C n − 1 j − 1 ] \sum_{i=1}^{maxVal}\sum_{j=1}^{log maxVal+1}[f(i,j)*C_{n-1}^{j-1}] ∑i=1maxVal∑j=1logmaxVal+1[f(i,j)∗Cn−1j−1]
class Solution {
int mod=(int)(1e9+7);
int maxLen=16;//对于没有重复元素的完美数组而言 最大值为10000 数组长度不会超过16
public int idealArrays(int n, int maxValue) {
ArrayList<ArrayList<Integer>> factors=new ArrayList<>();
for(int i=0;i<=maxValue;i++){
factors.add(new ArrayList<>());
}
//求元素i的因数
for(int i=1;i<=maxValue;i++){
for(int j=2*i;j<=maxValue;j+=i){
factors.get(j).add(i);
}
}
//求没有重复元素的f[i][j]
long[][]f=new long[maxValue+1][20];
for(int i=1;i<=maxValue;i++){
f[i][1]=1;
for(int j=2;j<=maxLen;j++){
for(int factor:factors.get(i)){
f[i][j]=(f[i][j]+f[factor][j-1])%mod;
}
}
}
//求组合数
long[][] C=new long[n+1][17];
C[0][0]=C[1][0]=C[1][1]=1;
for(int i=2;i<=n;i++){
C[i][0]=1;
for(int j=1;j<=i&&j<=maxLen;j++){
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
}
//求含有重复元素的完美数组的方案数
long ans=0;
for(int i=1;i<=maxValue;i++){
for(int j=1;j<=maxLen;j++){
ans=(ans+C[n-1][j-1]*f[i][j])%mod;
}
}
return (int)ans;
}
}