难度简单1
给你一个整数数组 nums
,数组由 不同正整数 组成,请你找出并返回数组中 任一 既不是 最小值 也不是 最大值 的数字,如果不存在这样的数字,返回 -1
。
返回所选整数。
示例 1:
输入:nums = [3,2,1,4]
输出:2
解释:在这个示例中,最小值是 1 ,最大值是 4 。因此,2 或 3 都是有效答案。
示例 2:
输入:nums = [1,2]
输出:-1
解释:由于不存在既不是最大值也不是最小值的数字,我们无法选出满足题目给定条件的数字。因此,不存在答案,返回 -1 。
示例 3:
输入:nums = [2,1,3]
输出:2
解释:2 既不是最小值,也不是最大值,这个示例只有这一个有效答案。
提示:
1 <= nums.length <= 100
1 <= nums[i] <= 100
nums
中的所有数字互不相同class Solution {
public int findNonMinOrMax(int[] nums) {
int mx = Integer.MIN_VALUE, mn = Integer.MAX_VALUE;
for(int num : nums){
mx = Math.max(mx, num);
mn = Math.min(mn, num);
}
for(int num : nums){
if(num != mx && num != mn)
return num;
}
return -1;
}
}
数组由 不同正整数 组成,只需要看前三个就行了
class Solution {
public int findNonMinOrMax(int[] nums) {
if (nums.length < 3) return -1;
Arrays.sort(nums, 0, 3); // 只对前三个数排序
return nums[1];
}
}
难度中等3
给你一个仅由小写英文字母组成的字符串 s
。在一步操作中,你可以完成以下行为:
s
的任一非空子字符串,可能是整个字符串,接着将字符串中的每一个字符替换为英文字母表中的前一个字符。例如,‘b’ 用 ‘a’ 替换,‘a’ 用 ‘z’ 替换。返回执行上述操作 恰好一次 后可以获得的 字典序最小 的字符串。
子字符串 是字符串中的一个连续字符序列。
现有长度相同的两个字符串 x
和 字符串 y
,在满足 x[i] != y[i]
的第一个位置 i
上,如果 x[i]
在字母表中先于 y[i]
出现,则认为字符串 x
比字符串 y
字典序更小 。
示例 1:
输入:s = "cbabc"
输出:"baabc"
解释:我们选择从下标 0 开始、到下标 1 结束的子字符串执行操作。
可以证明最终得到的字符串是字典序最小的。
示例 2:
输入:s = "acbbc"
输出:"abaab"
解释:我们选择从下标 1 开始、到下标 4 结束的子字符串执行操作。
可以证明最终得到的字符串是字典序最小的。
示例 3:
输入:s = "leetcode"
输出:"kddsbncd"
解释:我们选择整个字符串执行操作。
可以证明最终得到的字符串是字典序最小的。
提示:
1 <= s.length <= 3 * 105
s
仅由小写英文字母组成根据题意,把 a 替换成 z 会让字典序变大,所以子串里面是不能包含 a 的。
替换其它字符可以让字典序变小。
那么从左到右找到第一个不等于 a 的字符 s[i]
,并向后不断减一,直到 s 末尾或者遇到了 a。
class Solution {
public String smallestString(String s) {
char[] arr = s.toCharArray();
int n = arr.length;
int left = 0;
while(left < n && arr[left] == 'a') left += 1;
int right = left;
while(right < n && arr[right] != 'a') right += 1;
if(left == n){
arr[n-1] = 'z';
}else{
for(int i = left; i < right; i++){
int c = arr[i] - 'a';
c -= 1;
arr[i] = (char)('a' + c);
}
}
return new String(arr);
}
}
难度中等8
给你一个长度为 n
、下标从 0 开始的整数数组 nums
,表示收集不同巧克力的成本。每个巧克力都对应一个不同的类型,最初,位于下标 i
的巧克力就对应第 i
个类型。
在一步操作中,你可以用成本 x
执行下述行为:
0 <= i < n - 1
进行以下操作, 将下标 i
处的巧克力的类型更改为下标 (i + 1)
处的巧克力对应的类型。如果 i == n - 1
,则该巧克力的类型将会变更为下标 0
处巧克力对应的类型。假设你可以执行任意次操作,请返回收集所有类型巧克力所需的最小成本。
示例 1:
输入:nums = [20,1,15], x = 5
输出:13
解释:最开始,巧克力的类型分别是 [0,1,2] 。我们可以用成本 1 购买第 1 个类型的巧克力。
接着,我们用成本 5 执行一次操作,巧克力的类型变更为 [2,0,1] 。我们可以用成本 1 购买第 0 个类型的巧克力。
然后,我们用成本 5 执行一次操作,巧克力的类型变更为 [1,2,0] 。我们可以用成本 1 购买第 2 个类型的巧克力。
因此,收集所有类型的巧克力需要的总成本是 (1 + 5 + 1 + 5 + 1) = 13 。可以证明这是一种最优方案。
示例 2:
输入:nums = [1,2,3], x = 4
输出:6
解释:我们将会按最初的成本收集全部三个类型的巧克力,而不需执行任何操作。因此,收集所有类型的巧克力需要的总成本是 1 + 2 + 3 = 6 。
提示:
1 <= nums.length <= 1000
1 <= nums[i] <= 109
1 <= x <= 109
https://leetcode.cn/problems/collecting-chocolates/solution/qiao-miao-mei-ju-pythonjavacgo-by-endles-5ws2/
模拟过程详解:https://leetcode.cn/problems/collecting-chocolates/solution/mo-ni-guo-cheng-xiang-jie-java-by-tailta-ie4f/
如果不操作,第i个巧克力必须花费 nums[i]
收集,总成本为所有nums[i]
之和
如果操作一次,第i个巧克力可以花费 min(nums[i],nums[(i +1) mod n])
收集。注意在求和的情况下,把题意理解成循环左移还是循环右移,算出的结果都是一样的。(样例 1 解释中的类型变更是反过来的,但计算结果是正确的。)
如果操作两次,第 i 个巧克力可以花费 min(nums,nums[(i +1) mod n] , nums[(i + 2) mod n])
收集依此类推。
class Solution {
public long minCost(int[] nums, int x) {
int n = nums.length;
// sum数组:操作0次、1次、2次时得到的成本
// 预处理 sum数组统计操作 i 次的总花费 sum[i]
long[] sum = new long[n];
for(int i = 0; i < n; i++){
sum[i] = (long)i * x; // 操作i次的花费
}
for(int i = 0; i < n; i++){// 子数组左端点(枚举每一个类型,计算操作 0次、1次、2次时能购买的最小成本)
//计算每个类型可以购买的最小成本, O(n^2)
int mn = nums[i];
for(int j = i; j < n+i; j++){ // 子数组右端点(把数组视作环形的)
mn = Math.min(mn, nums[j % n]); // 从 nums[i] 到 nums[j%n] 的最小值
sum[j - i] += mn; // 累加操作 j-i 次的成本
}
}
long ans = Long.MAX_VALUE;
for(long s : sum)
ans = Math.min(ans, s);
return ans;
}
}
难度困难5
给你两个长度为 n
、下标从 0 开始的整数数组 nums1
和 nums2
,另给你一个下标从 1 开始的二维数组 queries
,其中 queries[i] = [xi, yi]
。
对于第 i
个查询,在所有满足 nums1[j] >= xi
且 nums2[j] >= yi
的下标 j
(0 <= j < n)
中,找出 nums1[j] + nums2[j]
的 最大值 ,如果不存在满足条件的 j
则返回 -1 。
返回数组 answer
*,*其中 answer[i]
是第 i
个查询的答案。
示例 1:
输入:nums1 = [4,3,1,2], nums2 = [2,4,9,5], queries = [[4,1],[1,3],[2,5]]
输出:[6,10,7]
解释:
对于第 1 个查询:xi = 4 且 yi = 1 ,可以选择下标 j = 0 ,此时 nums1[j] >= 4 且 nums2[j] >= 1 。nums1[j] + nums2[j] 等于 6 ,可以证明 6 是可以获得的最大值。
对于第 2 个查询:xi = 1 且 yi = 3 ,可以选择下标 j = 2 ,此时 nums1[j] >= 1 且 nums2[j] >= 3 。nums1[j] + nums2[j] 等于 10 ,可以证明 10 是可以获得的最大值。
对于第 3 个查询:xi = 2 且 yi = 5 ,可以选择下标 j = 3 ,此时 nums1[j] >= 2 且 nums2[j] >= 5 。nums1[j] + nums2[j] 等于 7 ,可以证明 7 是可以获得的最大值。
因此,我们返回 [6,10,7] 。
示例 2:
输入:nums1 = [3,2,5], nums2 = [2,3,4], queries = [[4,4],[3,2],[1,1]]
输出:[9,9,9]
解释:对于这个示例,我们可以选择下标 j = 2 ,该下标可以满足每个查询的限制。
示例 3:
输入:nums1 = [2,1], nums2 = [2,3], queries = [[3,3]]
输出:[-1]
解释:示例中的查询 xi = 3 且 yi = 3 。对于每个下标 j ,都只满足 nums1[j] < xi 或者 nums2[j] < yi 。因此,不存在答案。
提示:
nums1.length == nums2.length
n == nums1.length
1 <= n <= 105
1 <= nums1[i], nums2[i] <= 109
1 <= queries.length <= 105
queries[i].length == 2
xi == queries[i][1]
yi == queries[i][2]
1 <= xi, yi <= 109
题解:
关键一:答案要求与数组顺序无关,考虑从小到大排序
关键二:在知道所有询问的前提下, 可以从大到小(从小到大)进行回答
https://leetcode.cn/problems/maximum-sum-queries/solution/pai-xu-dan-diao-zhan-shang-er-fen-by-end-of9h/
class Solution {
public int[] maximumSumQueries(int[] nums1, int[] nums2, int[][] queries) {
int n = nums1.length;
int q = queries.length;
// 按 x 升序排序 nums1, nums2
Integer[] ids = new Integer[n];
for (int i = 0; i < n; i++) ids[i] = i;
Arrays.sort(ids, Comparator.comparingInt(o -> nums1[o]));
// 按 x 降序排序 queries
for (int i = 0; i < q; i++) {
queries[i] = new int[]{queries[i][0], queries[i][1], i};
}
Arrays.sort(queries, (o1, o2) -> Integer.compare(o2[0], o1[0]));
int[] ans = new int[q];
Arrays.fill(ans, -1);
Deque<int[]> stack = new ArrayDeque<>();
TreeMap<Integer, Integer> treeMap = new TreeMap<>();
int idx = n - 1;
for (int[] query : queries) {
int x = query[0], y = query[1], qId = query[2];
while (idx >= 0 && nums1[ids[idx]] >= x) {
int ax = nums1[ids[idx]], ay = nums2[ids[idx]];
// ay >= stack.peek()[0]
while (!stack.isEmpty() && stack.peek()[1] <= ax + ay) {
int[] pop = stack.pop();
treeMap.remove(pop[0]);
}
if (stack.isEmpty() || stack.peek()[0] < ay) {
stack.push(new int[]{ay, ax + ay});
treeMap.put(ay, ax + ay);
}
idx--;
}
// 单调栈上二分
Map.Entry<Integer, Integer> entry = treeMap.ceilingEntry(y);
if (entry != null) {
ans[qId] = entry.getValue();
}
}
return ans;
}
}