首先祝大家元宵节快乐!
6348. Take Gifts From the Richest Pile
给你一个整数数组 gifts ,表示各堆礼物的数量。每一秒,你需要执行以下操作:
- 选择礼物数量最多的那一堆。
- 如果不止一堆都符合礼物数量最多,从中选择任一堆即可。
- 选中的那一堆留下平方根数量的礼物(向下取整),取走其他的礼物。
返回在 k 秒后剩下的礼物数量。测试样例
输入:gifts = [25,64,9,4,100], k = 4
输出:29
解释:
按下述方式取走礼物:
- 在第一秒,选中最后一堆,剩下 10 个礼物。
- 接着第二秒选中第二堆礼物,剩下 8 个礼物。
- 然后选中第一堆礼物,剩下 5 个礼物。
- 最后,再次选中最后一堆礼物,剩下 3 个礼物。
最后剩下的礼物数量分别是 [5,8,9,4,3] ,所以,剩下礼物的总数量是 29 。
解答:优先队列寻找最大值,按照题意硬编码即可
class Solution {
public long pickGifts(int[] gifts, int k) {
PriorityQueue<Integer> queue = new PriorityQueue<>((a, b) -> (b.compareTo(a)));
for (int i : gifts) {
queue.add(i);
}
for (int i = 0; i < k; ++i) {
int tmp = queue.poll();
queue.add((int) Math.sqrt(tmp));
}
long res = 0;
for (int i : queue) {
res += i;
}
return res;
}
}
6347. Count Vowel Strings in Ranges
给你一个下标从 0 开始的字符串数组 words 以及一个二维整数数组 queries 。
每个查询 queries[i] = [li, ri] 会要求我们统计在 words 中下标在 li 到 ri 范围内(包含 这两个值)并且以元音开头和结尾的字符串的数目。
返回一个整数数组,其中数组的第 i 个元素对应第 i 个查询的答案。
注意:元音字母是 'a'、'e'、'i'、'o' 和 'u' 。
测试样例:
输入:words = ["aba","bcb","ece","aa","e"], queries = [[0,2],[1,4],[1,1]]
输出:[2,3,0]
解释:
以元音开头和结尾的字符串是 "aba"、"ece"、"aa" 和 "e" 。查询 [0,2] 结果为 2(字符串 "aba" 和 "ece")。查询 [1,4] 结果为 3(字符串 "ece"、"aa"、"e")。查询 [1,1] 结果为 0 。返回结果 [2,3,0] 。
解答: 按照题意,生成满足要求的字符串前缀和数组。然后根据query范围计算满足要求的字符串数量
class Solution {
private static final char[] vowels = {'a','e','i','o','u'};
public int[] vowelStrings(String[] words, int[][] queries) {
int len = words.length;
int[] mem = new int[len + 1];
for (int i = 0; i < len; ++i) {
mem[i + 1] = mem[i] + (isBeginEndWithVowels(words[i]) ? 1 : 0);
}
int[] res = new int[queries.length];
for (int i = 0; i < queries.length; ++i) {
res[i] = mem[queries[i][1] + 1] - mem[queries[i][0]];
}
return res;
}
private boolean isBeginEndWithVowels(String w) {
return isVowels(w.charAt(0)) && isVowels(w.charAt(w.length() - 1));
}
private boolean isVowels(char c) {
for (char v : vowels) {
if (v == c) return true;
}
return false;
}
}
6346. House Robber IV
沿街有一排连续的房屋。每间房屋内都藏有一定的现金。现在有一位小偷计划从这些房屋中窃取现金。
由于相邻的房屋装有相互连通的防盗系统,所以小偷 不会窃取相邻的房屋 。
小偷的 窃取能力 定义为他在窃取过程中能从单间房屋中窃取的 最大金额 。
给你一个整数数组 nums 表示每间房屋存放的现金金额。形式上,从左起第 i 间房屋中放有 nums[i] 美元。
另给你一个整数数组 k ,表示窃贼将会窃取的 最少 房屋数。小偷总能窃取至少 k 间房屋。
返回小偷的 最小 窃取能力。
测试样例
输入:nums = [2,3,5,9], k = 2
输出:5
解释:
小偷窃取至少 2 间房屋,共有 3 种方式:
- 窃取下标 0 和 2 处的房屋,窃取能力为 max(nums[0], nums[2]) = 5 。
- 窃取下标 0 和 3 处的房屋,窃取能力为 max(nums[0], nums[3]) = 9 。
- 窃取下标 1 和 3 处的房屋,窃取能力为 max(nums[1], nums[3]) = 9 。
因此,返回 min(5, 9, 9) = 5 。
解答:这道题目又是比较经典的二分查找题目。直观可以知道,窃取能力越大,则满足要求的房间越多,小偷可以实施的偷窃数量越多,即存在单调性。我们利用二分查找,寻找第一个满足要求的盗窃能力
class Solution {
public int minCapability(int[] nums, int k) {
int min = 1, max = findMax(nums);
while (min < max) {
int mid = (min + max) / 2;
if (familyCount(nums, mid) >= k) {
max = mid;
} else {
min = mid + 1;
}
}
return min;
}
private int findMax(int[] nums) {
int max = 0;
for (int i : nums) {
max = Math.max(max, i);
}
return max;
}
private int familyCount(int[] nums, int mid) {
int[] steal = {0,0}, pos = {-1,-1};
for (int i = 0; i < nums.length; ++i) {
if (nums[i] <= mid) {
int cur;
if (i == pos[1] + 1) {
cur = steal[0] + 1;
} else {
cur = steal[1] + 1;
}
steal[0] = Math.max(steal[0], steal[1]);
steal[1] = Math.max(steal[1], cur);
pos[0] = pos[1];
pos[1] = i;
}
}
return steal[1];
}
}
6345. Rearranging Fruits
你有两个果篮,每个果篮中有 n 个水果。给你两个下标从 0 开始的整数数组 basket1 和 basket2 ,用以表示两个果篮中每个水果的成本。
你希望两个果篮相等。为此,可以根据需要多次执行下述操作:
- 选中两个下标 i 和 j ,并交换 basket1 中的第 i 个水果和 basket2 中的第 j 个水果。
- 交换的成本是 min(basket1i,basket2j) 。
根据果篮中水果的成本进行排序,如果排序后结果完全相同,则认为两个果篮相等。
返回使两个果篮相等的最小交换成本,如果无法使两个果篮相等,则返回 -1 。
测试样例
输入:basket1 = [4,2,2,2], basket2 = [1,4,1,2]
输出:1
解释:
交换 basket1 中下标为 1 的水果和 basket2 中下标为 0 的水果,交换的成本为 1 。此时,basket1 = [4,1,2,2] 且 basket2 = [2,4,1,2] 。重排两个数组,发现二者相等。
解答:这道题又又又是脑筋急转弯。一共可以分成三步:
- 判断数组是否满足有求,即所有出现的元素都是偶数次数,否则无法做到2个数组一致
- 计算basket1缺少和多余的水果
- 尽量用cost小的水果换cost大的水果,同时注意如果cost小的水果也大于2倍最小水果cost话,可以利用最小cost的水果作为中转完成计算
class Solution {
public long minCost(int[] basket1, int[] basket2) {
if (!isValid(basket1, basket2)) return -1;
int min = Integer.MAX_VALUE;
Map<Integer, Integer> map = new HashMap<>();
for (int i : basket1) {
min = Math.min(min, i);
map.put(i, map.getOrDefault(i, 0) + 1);
}
for (int i : basket2) {
min = Math.min(min, i);
map.put(i, map.getOrDefault(i, 0) - 1);
}
List<Integer> more = new ArrayList<>(), less = new ArrayList<>();
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() > 0) {
int time = entry.getValue() / 2;
for (int i = 0; i < time; ++i) {
more.add(entry.getKey());
}
} else if (entry.getValue() < 0) {
int time = -entry.getValue() / 2;
for (int i = 0; i < time; ++i) {
less.add(entry.getKey());
}
}
}
long res = 0;
int l = 0, r = more.size() - 1;
while (r >= 0) {
int tm = Math.min(more.get(l), less.get(r));
if (tm >= 2L * min) {
res = res + 2L * min;
} else {
res = res + tm;
}
++l;
--r;
}
return res;
}
private boolean isValid(int[] basket1, int[] basket2) {
Map<Integer, Integer> map = new HashMap<>();
for (int i : basket1) {
map.put(i, map.getOrDefault(i, 0) + 1);
}
for (int i : basket2) {
map.put(i, map.getOrDefault(i, 0) + 1);
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() % 2 == 1) return false;
}
return true;
}
}