给你一个数组 prices ,其中 prices[i] 是商店里第 i 件商品的价格。商店里正在进行促销活动,如果你要买第 i 件商品,那么你可以得到与 prices[j] 相等的折扣,其中 j 是满足 j > i 且 prices[j] <= prices[i] 的 最小下标 ,如果没有满足条件的 j ,你将没有任何折扣。请你返回一个数组,数组中第 i 个元素是折扣后你购买商品 i 最终需要支付的价格。
示例 1:
输入:prices = [8,4,6,2,3]
输出:[4,2,4,2,3]
解释:
商品 0 的价格为 price[0]=8 ,你将得到 prices[1]=4 的折扣,所以最终价格为 8 - 4 = 4 。
商品 1 的价格为 price[1]=4 ,你将得到 prices[3]=2 的折扣,所以最终价格为 4 - 2 = 2 。
商品 2 的价格为 price[2]=6 ,你将得到 prices[3]=2 的折扣,所以最终价格为 6 - 2 = 4 。
商品 3 和 4 都没有折扣。
示例 2:
输入:prices = [1,2,3,4,5]
输出:[1,2,3,4,5]
解释:在这个例子中,所有商品都没有折扣。
示例 3:
输入:prices = [10,1,1,6]
输出:[9,0,1,6]
最先想到的就是暴力解法,维护一个数组sub
作为每个prices[i]
折扣的价格,那么结果数组中res
的元素即为:
r e s [ i ] = p r i c e s [ i ] − s u b [ i ] res[i] = prices[i] - sub[i] res[i]=prices[i]−sub[i]
class Solution {
public int[] finalPrices(int[] prices) {
int[] res = new int[prices.length];
int[] sub = new int[prices.length];
sub[prices.length - 1] = 0;
for (int i = 0; i < prices.length - 1; i++) {
for (int j = i + 1; j < prices.length; j++) {
if (prices[j] <= prices[i]) {
sub[i] = prices[j];
break;
}
}
}
for (int i = 0; i < prices.length; i++) {
res[i] = prices[i] - sub[i];
}
return res;
}
}
暴力解法的时间复杂度O(n2),
单调栈解法:
class Solution {
public int[] finalPrices(int[] prices) {
if (prices == null || prices.length <= 1) return prices;
Deque<Integer> stack = new LinkedList<>();
int[] res = new int[prices.length];
for (int i = 0; i < prices.length; i++) {
while (!stack.isEmpty() && prices[stack.peek()] >= prices[i]) {
int pop = stack.pop();
res[pop] = prices[pop] - prices[i];
}
stack.push(i);
}
while (!stack.isEmpty()) {
int pop = stack.pop();
res[pop] = prices[pop];
}
return res;
}
}
给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。请返回 nums 的动态和。
示例 1:
输入:nums = [1,2,3,4]
输出:[1,3,6,10]
解释:动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4] 。
示例 2:
输入:nums = [1,1,1,1,1]
输出:[1,2,3,4,5]
解释:动态和计算过程为 [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1] 。
示例 3:
输入:nums = [3,1,2,10,1]
输出:[3,4,6,16,17]
此题其实就是前缀和(prefix sum),很容易即可解答:
class Solution {
public int[] runningSum(int[] nums) {
int[] ps = new int[nums.length];
ps[0] = nums[0];
for(int i = 1; i < nums.length; i++){
ps[i] = ps[i - 1] + nums[i];
}
return ps;
}
}
给你一个整数数组 arr 和一个整数 k 。现需要从数组中恰好移除 k 个元素,请找出移除后数组中不同整数的最少数目。
示例 1:
输入:arr = [5,5,4], k = 1
输出:1
解释:移除 1 个 4 ,数组中只剩下 5 一种整数。
示例 2:
输入:arr = [4,3,1,1,3,3,2], k = 3
输出:2
解释:先移除 4、2 ,然后再移除两个 1 中的任意 1 个或者三个 3 中的任意 1 个,最后剩下 1 和 3 两种整数。
用HashMap存储每个数组出现的次数,然后根据将数组按照出现次数从小到大排序,然后从数组开始移除k个元素,剩下的元素统计其不同元素个数(通过哈希集),得到结果个数即为结果。
class Solution {
public int findLeastNumOfUniqueInts(int[] arr, int k) {
Map<Integer, Integer> map = new HashMap<>(); //记录每个数字的个数
for (int i = 0; i < arr.length; i++) {
if (!map.keySet().contains(arr[i])) map.put(arr[i], 1);
else {
int update = map.get(arr[i]) + 1;
map.put(arr[i], update);
}
}
List<Map.Entry<Integer, Integer>> list = new ArrayList<>(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
List<Integer> sorted = new ArrayList<>();
for (Map.Entry<Integer, Integer> entry : list) {
for (int i = 0; i < entry.getValue(); i++) {
sorted.add(entry.getKey());
}
}
Deque<Integer> linkedlist = new LinkedList<>();
for (int i : sorted) linkedlist.add(i);
for (int i = 0; i < k; i++) {
linkedlist.pollFirst();
}
HashSet<Integer> set = new HashSet<>();
for (int i : linkedlist) set.add(i);
return set.size();
}
}
上面是我写的代码,同样的思路,看了大佬的代码,觉得自己写的垃圾死了:
class Solution {
public int findLeastNumOfUniqueInts(int[] arr, int k) {
Map<Integer, Integer> cnt = new HashMap(arr.length);
for(int x : arr){
cnt.put(x, cnt.getOrDefault(x, 0) + 1);
}
List<Map.Entry<Integer, Integer>> list = new ArrayList(cnt.entrySet());
list.sort((a, b) -> a.getValue().compareTo(b.getValue()));
int ans = list.size();
for(int i = 0; i < list.size(); i++){
Map.Entry<Integer, Integer> ele = list.get(i);
if(ele.getValue() > k){
break;
}
ans--;
k -= ele.getValue();
}
return ans;
}
}
给你一个整数数组 bloomDay,以及两个整数 m 和 k 。现需要制作 m 束花。制作花束时,需要使用花园中 相邻的 k 朵花 。花园中有 n 朵花,第 i 朵花会在 bloomDay[i] 时盛开,恰好 可以用于 一束 花中。请你返回从花园中摘 m 束花需要等待的最少的天数。如果不能摘到 m 束花则返回 -1 。
示例 1:
输入:bloomDay = [1,10,3,10,2], m = 3, k = 1
输出:3
解释:让我们一起观察这三天的花开过程,x 表示花开,而 _ 表示花还未开。
现在需要制作 3 束花,每束只需要 1 朵。
1 天后:[x, _, _, _, _] // 只能制作 1 束花
2 天后:[x, _, _, _, x] // 只能制作 2 束花
3 天后:[x, _, x, _, x] // 可以制作 3 束花,答案为 3
示例 2:
输入:bloomDay = [1,10,3,10,2], m = 3, k = 2
输出:-1
解释:要制作 3 束花,每束需要 2 朵花,也就是一共需要 6 朵花。而花园中只有 5 朵花,无法满足制作要求,返回 -1 。
示例 3:
输入:bloomDay = [7,7,7,7,12,7,7], m = 2, k = 3
输出:12
解释:要制作 2 束花,每束需要 3 朵。
花园在 7 天后和 12 天后的情况如下:
7 天后:[x, x, x, x, _, x, x]
可以用前 3 朵盛开的花制作第一束花。但不能使用后 3 朵盛开的花,因为它们不相邻。
12 天后:[x, x, x, x, x, x, x]
显然,我们可以用不同的方式制作两束花。
示例 4:
输入:bloomDay = [1000000000,1000000000], m = 1, k = 1
输出:1000000000
解释:需要等 1000000000 天才能采到花来制作花束
示例 5:
输入:bloomDay = [1,10,2,9,3,8,4,7,5,6], m = 4, k = 2
输出:9
class Solution {
public int minDays(int[] b, int m, int k) {
int inf = (int)1e9 + 1;
int l = 0;
int r = inf;
while(l < r){
int mid = (l + r) / 2;
if(check(b, m, k, mid)){
r = mid;
}else{
l = mid + 1;
}
}
return l == inf ? -1 : l;
}
public boolean check(int[] b, int m, int k, int t){
int cnt = 0;
int total = 0;
for(int i = 0; i < b.length; i++){
if(b[i] > t){
cnt = 0;
continue;
}
cnt++;
if(cnt == k){
total++;
cnt = 0;
}
}
return total >= m;
}
}