- 1984. Minimum Difference Between Highest and Lowest of K Scores(Easy)
- 1985. Find the Kth Largest Integer in the Array(Medium)
- 1986. Minimum Number of Work Sessions to Finish the Tasks(Medium)
- 1987. Number of Unique Good Subsequences(Hard)
1984. Minimum Difference Between Highest and Lowest of K Scores(Easy)
给你一个 下标从 0 开始 的整数数组 nums ,其中 nums[i] 表示第 i 名学生的分数。另给你一个整数 k 。
从数组中选出任意 k 名学生的分数,使这 k 个分数间 最高分 和 最低分 的 差值 达到 最小化 。
返回可能的 最小差值 。
示例 1:
输入:nums = [90], k = 1
输出:0
解释:选出 1 名学生的分数,仅有 1 种方法:
- [90] 最高分和最低分之间的差值是 90 - 90 = 0
可能的最小差值是 0
示例 2:
输入:nums = [9,4,1,7], k = 2
输出:2
解释:选出 2 名学生的分数,有 6 种方法:
- [9,4,1,7] 最高分和最低分之间的差值是 9 - 4 = 5
- [9,4,1,7] 最高分和最低分之间的差值是 9 - 1 = 8
- [9,4,1,7] 最高分和最低分之间的差值是 9 - 7 = 2
- [9,4,1,7] 最高分和最低分之间的差值是 4 - 1 = 3
- [9,4,1,7] 最高分和最低分之间的差值是 7 - 4 = 3
- [9,4,1,7] 最高分和最低分之间的差值是 7 - 1 = 6
可能的最小差值是 2
解题思路:先排序再求解最小差值
class Solution {
public:
int minimumDifference(vector<int>& nums, int k) {
if(k == 1)
return 0;
sort(nums.begin(), nums.end());
int min_dif = 999999;
for(int i = 0; i+k-1 < nums.size(); i++){
min_dif = min(min_dif, nums[i+k-1] - nums[i]);
}
return min_dif;
}
};
1985. Find the Kth Largest Integer in the Array(Medium)
给你一个字符串数组 nums 和一个整数 k 。nums 中的每个字符串都表示一个不含前导零的整数。
返回 nums 中表示第 k 大整数的字符串。
注意:重复的数字在统计时会视为不同元素考虑。例如,如果 nums 是 [“1”,“2”,“2”],那么 “2” 是最大的整数,“2” 是第二大的整数,“1” 是第三大的整数。
示例 1:
输入:nums = [“3”,“6”,“7”,“10”], k = 4
输出:“3”
解释:
nums 中的数字按非递减顺序排列为 [“3”,“6”,“7”,“10”]
其中第 4 大整数是 “3”
示例 2:
输入:nums = [“2”,“21”,“12”,“1”], k = 3
输出:“2”
解释:
nums 中的数字按非递减顺序排列为 [“1”,“2”,“12”,“21”]
其中第 3 大整数是 “2”
示例 3:
输入:nums = [“0”,“0”], k = 2
输出:“0”
解释:
nums 中的数字按非递减顺序排列为 [“0”,“0”]
其中第 2 大整数是 “0”
解题思路:先排序,排序使用自定义的比较函数,直接比较字符串大小,先比较长度,相同长度的再逐位比较大小。
bool cmp(string& a, string& b){
if(a.size() != b.size())
return a.size() > b.size();
for(int i = 0;i < a.size(); i++)
if(a[i] != b[i])
return a[i] > b[i];
return false;
}
class Solution {
public:
string kthLargestNumber(vector<string>& nums, int k) {
sort(nums.begin(), nums.end(), cmp);
// for(int i = 0;i < nums.size(); i++)
// cout << nums[i] << " ";
return nums[k-1];
}
};
1986. Minimum Number of Work Sessions to Finish the Tasks(Medium)
你被安排了 n 个任务。任务需要花费的时间用长度为 n 的整数数组 tasks 表示,第 i 个任务需要花费 tasks[i] 小时完成。一个 工作时间段 中,你可以 至多 连续工作 sessionTime 个小时,然后休息一会儿。
你需要按照如下条件完成给定任务:
如果你在某一个时间段开始一个任务,你需要在 同一个 时间段完成它。
完成一个任务后,你可以 立马 开始一个新的任务。
你可以按 任意顺序 完成任务。
给你 tasks 和 sessionTime ,请你按照上述要求,返回完成所有任务所需要的 最少 数目的 工作时间段 。
测试数据保证 sessionTime 大于等于 tasks[i] 中的 最大值 。
示例 1:
输入:tasks = [1,2,3], sessionTime = 3
输出:2
解释:你可以在两个工作时间段内完成所有任务。
第一个工作时间段:完成第一和第二个任务,花费 1 + 2 = 3 小时。
第二个工作时间段:完成第三个任务,花费 3 小时。
示例 2:
输入:tasks = [3,1,3,1,1], sessionTime = 8
输出:2
解释:你可以在两个工作时间段内完成所有任务。
第一个工作时间段:完成除了最后一个任务以外的所有任务,花费 3 + 1 + 3 + 1 = 8 小时。
第二个工作时间段,完成最后一个任务,花费 1 小时。
示例 3:
输入:tasks = [1,2,3,4,5], sessionTime = 15
输出:1
解释:你可以在一个工作时间段以内完成所有任务。
解题思路(参考自讨论区 链接):本题task数量不多,所以可以使用比较暴力的搜索方法,先计算所有task使用的时间的和,得到session的个数的上下界,然后进行搜索。搜索的过程用到回溯的思路如果当前这个task能够在第j个session完成,则尝试,如果后面的task都能完成则可以完成,否则修改回原来的状态,也就是不在第j个session完成这个task。
bool cmp(int& a, int& b){
return a > b;
}
class Solution {
public:
bool can_partion(int index, int& sessionTime, vector<int>& tasks, vector<int>& sessions){
if(index == tasks.size())
return true;
for(int i = 0;i < sessions.size(); i++){
if(sessions[i] + tasks[index] <= sessionTime){
sessions[i] += tasks[index];
if(can_partion(index+1, sessionTime, tasks, sessions))
return true;
else
sessions[i] -= tasks[index];
}
}
return false;
}
int minSessions(vector<int>& tasks, int sessionTime) {
sort(tasks.begin(), tasks.end(), cmp);
int minv = 9999999, sum = 0;
for(int i = 0;i < tasks.size(); i++){
minv = min(tasks[i], minv);
sum += tasks[i];
}
if(minv >= sessionTime)
return tasks.size();
if(sum <= sessionTime)
return 1;
int k_min = sum / sessionTime;
int k_max = tasks.size();
for(int k=k_min; k < k_max; k++){
vector<int> sessions(k, 0);
if(can_partion(0, sessionTime, tasks, sessions))
return k;
}
return k_max;
}
};
1987. Number of Unique Good Subsequences(Hard)
给你一个二进制字符串 binary 。 binary 的一个 子序列 如果是 非空 的且没有 前导 0 (除非数字是 “0” 本身),那么它就是一个 好 的子序列。
请你找到 binary 不同好子序列 的数目。
比方说,如果 binary = “001” ,那么所有 好 子序列为 [“0”, “0”, “1”] ,所以 不同 的好子序列为 “0” 和 “1” 。 注意,子序列 “00” ,“01” 和 “001” 不是好的,因为它们有前导 0 。
请你返回 binary 中 不同好子序列 的数目。由于答案可能很大,请将它对 109 + 7 取余 后返回。
一个 子序列 指的是从原数组中删除若干个(可以一个也不删除)元素后,不改变剩余元素顺序得到的序列。
示例 1:
输入:binary = “001”
输出:2
解释:好的二进制子序列为 [“0”, “0”, “1”] 。
不同的好子序列为 “0” 和 “1” 。
示例 2:
输入:binary = “11”
输出:2
解释:好的二进制子序列为 [“1”, “1”, “11”] 。
不同的好子序列为 “1” 和 “11” 。
示例 3:
输入:binary = “101”
输出:5
解释:好的二进制子序列为 [“1”, “0”, “1”, “10”, “11”, “101”] 。
不同的好子序列为 “0” ,“1” ,“10” ,“11” 和 “101” 。
解题思路(参考自讨论区 链接):首先想到的就是使用动态规划的方法,然后自然就想到怎么构造子问题,然后问题就转换为了假设现在处理的字符串长度为n,如果已经有了长度为n-1的答案,如何使用长度为n-1的答案以及第n位的值得到结果,也就是递推公式。具体递推过程见参考链接,这里解释下我自己看的时候的一个困惑就是为什么在遇到1时要+1
评论区这个表格很好的解释了这个问题,就是在遇到1时,我们是想要把1加到之前得到的所有满足条件的子串后,这就有一个问题,之前的子串集合中是有“1”的,但是在我新遇到一个1后就没有了(因为原来的那个“1”变成了“11”),这同时也说明了“0”为什么不加1,因为“0”这个子串是用has0这个变量加的,不用在这里加。
class Solution {
public:
int numberOfUniqueGoodSubsequences(string binary) {
int n = binary.size();
vector<int> dp(2, 0);
int mod = 1e9 + 7;
int has0 = 0;
for(int i = 0;i < n; i++){
dp[binary[i] - '0'] = (dp[0] + dp[1] + binary[i] - '0') % mod;
if(binary[i] == '0')
has0 = 1;
}
return (dp[0] + dp[1] + has0) % mod;
}
};