-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
80 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
--- | ||
layout: post | ||
title: 2024-06-13-力扣2813.子序列最大优雅度 | ||
date: 2024-06-13 10:59:24 | ||
excerpt_type: html # <!-- more -->标签渲染方式 | ||
updated: 2024-06-13 | ||
categories: 力扣好题记录 | ||
tags: | ||
- Java | ||
- 算法 | ||
- 贪心 | ||
- 力扣 | ||
--- | ||
|
||
|
||
## 力扣2813.子序列最大优雅度 | ||
|
||
[2813.子序列最大优雅度](https://leetcode.cn/problems/maximum-elegance-of-a-k-length-subsequence/solutions/2807350/zi-xu-lie-zui-da-you-ya-du-by-leetcode-s-mw6g/?envType=daily-question&envId=2024-06-13) | ||
|
||
有一点思路,但不多。 | ||
|
||
<!-- more --> | ||
|
||
不看提示的时候大概能够想到要用贪心,本来想的是先排序,并且时刻维护两个元素,其中第一个元素记录已经重复类别的未选择最大值,第二个元素记录不重复类别的未选择最大值。但是这样选到第k个之后就无法继续选择了。 | ||
|
||
看完提示之后对于如何维护这k个元素感到疑惑,还以为是另外建立一个集合来维护。 | ||
|
||
于是直接看题解,思路理解如下: | ||
|
||
- 维护已选择的k个元素使用的数据结构是栈,并且栈中仅存储重复了的元素,因为利润较大且不重复的元素一定比之后利润较小且不重复的元素要好,因此仅重复元素有要被删除的可能。此外,在删除元素时,仅需要考虑**重复**且**最小**的那个元素,对于这个元素具体是什么类别无需关心,因此使用一个从栈底到栈顶递减的栈来存储重复了的元素(不包括每个类别的第一个元素),需要删除元素时删除栈顶的元素即可。 | ||
|
||
- 虽然在存储了前k个元素之后,删除元素并添加新元素可能会导致总结果降低,但是可以每次在替换元素时都存储一次当前结果(如果当前比之前的最大值要更大),因此不需要考虑在替换元素的过程中结果变小了怎么办。 | ||
|
||
代码: | ||
|
||
```java | ||
class Solution { | ||
public long findMaximumElegance(int[][] items, int k) { | ||
int n = items.length; | ||
Arrays.sort(items, (a, b)-> -(a[0]-b[0])); // 按照利润值降序排列 | ||
long total = 0; | ||
long cat_num = 0; | ||
long ans = 0; | ||
Set<Integer> categories = new HashSet<>(); // 存储已经出现过的类别 | ||
Deque<Integer> deque = new LinkedList<>(); | ||
for(int i=0;i<k;i++){ | ||
//前k个数,直接入set,如果重复则加入栈中 | ||
//每个类别第一次出现的数(最大数)不会入栈,即不会被删除 | ||
if(categories.contains(items[i][1])==false){ | ||
categories.add(items[i][1]); | ||
cat_num += 1; | ||
} | ||
else{ | ||
deque.offerFirst(items[i][0]); | ||
} | ||
total += items[i][0]; | ||
} | ||
ans = total + cat_num*cat_num; | ||
for(int i=k;i<n;i++){ | ||
//接下来的数字,如果类别已经出现过,则不要 | ||
//如果类别没有出现过,则替换掉之前一个重复数字,并且计算一次最大值 | ||
if(categories.contains(items[i][1])){ | ||
continue; | ||
} | ||
else if(deque.size()>0){ | ||
categories.add(items[i][1]); | ||
int minus = deque.pollFirst(); | ||
total += items[i][0]-minus; | ||
cat_num += 1; | ||
ans = Math.max(ans, total + cat_num*cat_num); | ||
} | ||
} | ||
return ans; | ||
} | ||
} | ||
``` | ||
|
||
时间复杂度:$O(n \times logn)$,即排序的时间复杂度。排序后仅需要一次遍历即可。 | ||
|
||
空间复杂度:$O(n)$,当元素全都不重复时的Set所用空间,或者元素全重复时的栈空间。 |