LeetCode 2813. Maximum Elegance of a K-Length Subsequence【反悔貪心】2582

本文屬于「征服LeetCode」系列文章之一,這一系列正式開始于2021/08/12。由于LeetCode上部分題目有鎖,本系列將至少持續到刷完所有無鎖題之日為止;由于LeetCode還在不斷地創建新題,本系列的終止日期可能是永遠。在這一系列刷題文章中,我不僅會講解多種解題思路及其優化,還會用多種編程語言實現題解,涉及到通用解法時更將歸納總結出相應的算法模板。

為了方便在PC上運行調試、分享代碼文件,我還建立了相關的倉庫:https://github.com/memcpy0/LeetCode-Conquest。在這一倉庫中,你不僅可以看到LeetCode原題鏈接、題解代碼、題解文章鏈接、同類題目歸納、通用解法總結等,還可以看到原題出現頻率和相關企業等重要信息。如果有其他優選題解,還可以一同分享給他人。

由于本系列文章的內容隨時可能發生更新變動,歡迎關注和收藏征服LeetCode系列文章目錄一文以作備忘。

給你一個長度為?n?的二維整數數組?items?和一個整數?k?。

items[i] = [profiti, categoryi],其中?profiti?和?categoryi?分別表示第?i?個項目的利潤和類別。

現定義?items?的?子序列?的?優雅度?可以用?total_profit + distinct_categories2?計算,其中?total_profit?是子序列中所有項目的利潤總和,distinct_categories?是所選子序列所含的所有類別中不同類別的數量。

你的任務是從?items?所有長度為?k?的子序列中,找出?最大優雅度?。

用整數形式表示并返回?items?中所有長度恰好為?k?的子序列的最大優雅度。

注意: 數組的子序列是經由原數組刪除一些元素(可能不刪除)而產生的新數組,且刪除不改變其余元素相對順序。

示例 1:

輸入:items = [[3,2],[5,1],[10,1]], k = 2
輸出:17
解釋:
在這個例子中,我們需要選出長度為 2 的子序列。
其中一種方案是 items[0] = [3,2] 和 items[2] = [10,1] 。
子序列的總利潤為 3 + 10 = 13 ,子序列包含 2 種不同類別 [2,1] 。
因此,優雅度為 13 + 22 = 17 ,可以證明 17 是可以獲得的最大優雅度。

示例 2:

輸入:items = [[3,1],[3,1],[2,2],[5,3]], k = 3
輸出:19
解釋:
在這個例子中,我們需要選出長度為 3 的子序列。 
其中一種方案是 items[0] = [3,1] ,items[2] = [2,2] 和 items[3] = [5,3] 。
子序列的總利潤為 3 + 2 + 5 = 10 ,子序列包含 3 種不同類別 [1, 2, 3] 。 
因此,優雅度為 10 + 32 = 19 ,可以證明 19 是可以獲得的最大優雅度。

示例 3:

輸入:items = [[1,1],[2,1],[3,1]], k = 3
輸出:7
解釋:
在這個例子中,我們需要選出長度為 3 的子序列。
我們需要選中所有項目。
子序列的總利潤為 1 + 2 + 3 = 6,子序列包含 1 種不同類別 [1] 。
因此,最大優雅度為 6 + 12 = 7 。

提示:

  • 1 <= items.length == n <= 10^5
  • items[i].length == 2
  • items[i][0] == profiti
  • items[i][1] == categoryi
  • 1 <= profiti <= 10^9
  • 1 <= categoryi <= n
  • 1 <= k <= n

解法 反悔貪心

按照利潤從大到小排序。先把前 k k k 個項目選上。

考慮選第 k + 1 k+1 k+1 個項目,為了選它,我們必須從前 k k k 個項目中移除一個項目。由于已經按照利潤從大到小排序,選這個項目不會讓 t o t a l _ p r o f i t total\_profit total_profit 變大,所以我們重點考慮能否讓 d i s t i n c t _ c a t e g o r i e s distinct\_categories distinct_categories 變大。分類討論:

  1. 如果第 k + 1 k+1 k+1 個項目和前面某個已選項目的類別相同,那么無論怎么移除都不會讓 d i s t i n c t _ c a t e g o r i e s distinct\_categories distinct_categories 變大,所以無需選擇這個項目。
  2. 如果第 k + 1 k+1 k+1 個項目和前面任何已選項目的類別都不一樣,考慮移除前面已選項目中的哪一個:
    1. 如果移除的項目的類別只出現一次,那么選第 k + 1 k+1 k+1 個項目后, d i s t i n c t _ c a t e g o r i e s distinct\_categories distinct_categories 一減一增,保持不變,所以不考慮這種情況。
    2. 如果移除的項目的類別重復出現多次,那么選第 k + 1 k+1 k+1 個項目后, d i s t i n c t _ c a t e g o r i e s distinct\_categories distinct_categories 會增加一,此時有可能會讓優雅度變大,一定要選擇這個項目。為什么說「一定」呢?因為 t o t a l _ p r o f i t total\_profit total_profit 只會變小,我們現在的目標就是讓 t o t a l _ p r o f i t total\_profit total_profit 保持盡量大,同時讓 d i s t i n c t _ c a t e g o r i e s distinct\_categories distinct_categories 增加,那么能讓 d i s t i n c t _ c a t e g o r i e s distinct\_categories distinct_categories 增加就立刻選上!因為后面的利潤更小,現在不選的話將來 t o t a l _ p r o f i t total\_profit total_profit 只會更小。

按照這個過程,繼續考慮選擇后面的項目。計算優雅度,取最大值,即為答案。

代碼實現時,應移除已選項目中類別和前面重復利潤最小的項目,這可以用一個棧 d u p l i c a t e duplicate duplicate 來維護,由于利潤從大到小排序,所以棧頂就是最小的利潤;前面 k k k 次中如果出現了多個重復項,則在棧中也會有多個項。注意,對于后面的項目,由于我們只考慮之前沒出現過的類別,也就是說這個后面的項目的類別只出現了一次,所以不應當加到 d u p l i c a t e duplicate duplicate 中。

class Solution {
public:long long findMaximumElegance(vector<vector<int>>& items, int k) {// 利潤從大到小排序sort(items.begin(), items.end(), [&](const auto &a, const auto &b) {return a[0] > b[0];});long long totalProfit = 0, ans = 0;// 利潤和 totalProfit 在最大 k 個利潤的基礎上不會變大unordered_set<int> vis; // 判斷類別是否出現過stack<int> dup; // 重復類別的利潤,棧頂最小for (int i = 0, n = items.size(); i < n; ++i) {int profit = items[i][0], category = items[i][1];if (i < k) {totalProfit += profit;if (vis.count(category)) dup.push(profit);else vis.insert(category);} // 如果新添加的項目的類別之前選過了,則distinct_categories不會變大 else if (!dup.empty() && !vis.count(category)) {// 如果新添加的項目的類別之前沒有選過,distinct_categories^2可能變大vis.insert(category);// 我們移除最小利潤的項目// 如果移除的項目的類別只有1個,則distinct_categories-1+1,不變,但總利潤可能變小// 如果移除的項目的類別有多個,則distinct_categories+1,這種情況就是可行的totalProfit -= dup.top(); dup.pop(); // 移除掉一個重復且利潤最小的項目totalProfit += profit; // 本項目目前只出現了一次,不應加入dup中;且以后出現也不會被考慮}ans = max(ans, totalProfit + (long long)(vis.size() * vis.size()));}return ans;}
};

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/35693.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/35693.shtml
英文地址,請注明出處:http://en.pswp.cn/news/35693.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaWeb中Json傳參的條件

JavaWeb中我們常用json進行參數傳遞 對應的注釋為RequestBody 但是json傳參是有條件的 最主要是你指定的實體類和對應的json參數能否匹配 1.屬性和對應的json參數名稱對應 2.對應實體類實現了Serializable接口&#xff0c;可以進行序列化和反序列化&#xff0c;這個才是實體類轉…

黑馬項目一階段面試58題 Web14題(二)

八、內連接和外連接查詢有什么區別 內連接 獲取兩表的交集部分 外連接 獲取某表的所有數據&#xff0c;以及兩表的交集數據 九、事務管理的作用&#xff0c;四大特性 作用 保證多個增刪改的操作&#xff0c;要么同時成功&#xff0c;要么同時失敗 四大特性 1.原子性 事…

Ajax同源策略及跨域問題

Ajax同源策略及跨域問題 同源策略ajax跨域問題什么是跨域&#xff1f;為什么不允許跨域&#xff1f;跨域解決方案1、CORS2、express自帶的中間件cors3、JSONP原生JSONPjQuery發送JSONP 4、使用vscode的Live Server插件 同源策略 同源策略&#xff08;Same-Origin Policy&#…

Kotlin入門:程序的邏輯控制——03

一、程序的邏輯控制 程序的執行語句主要分為3種&#xff1a;順序語句、條件語句和循環語句。 二、if條件語句 if表達式在Kotlin中用于根據條件執行不同的代碼塊。它有兩種形式&#xff1a;普通if和帶返回值的if。 普通if語句&#xff1a; 普通的if語句由關鍵字if、一個布爾表達…

電腦合上蓋子無線網絡不會斷開

控制面板\硬件和聲音\電源選項\系統設置 最終選擇不會采取任何操作 選擇不會采取任何操作

前端性能優化之性能優化的指標和工具(chrome devtools、lighthouse、webpagetest)

文章目錄 引言一、為什么要進行web性能優化二、RAIL測量模型1. 什么是RAIL2. 性能測量工具 三、性能測量工具的使用和性能指標以及優化目標1. Chrome DevTools1. 打開調試工具方式和配置2. network下的幾個性能指標1. requests 請求總數2. transferred實際從服務器下載的數據量…

【數據結構與算法】十大經典排序算法-希爾排序

&#x1f31f;個人博客&#xff1a;www.hellocode.top &#x1f3f0;Java知識導航&#xff1a;Java-Navigate &#x1f525;CSDN&#xff1a;HelloCode. &#x1f31e;知乎&#xff1a;HelloCode &#x1f334;掘金&#xff1a;HelloCode ?如有問題&#xff0c;歡迎指正&#…

手撕數據結構之棧+例題

目錄 一、棧的概念及結構 二、棧的頭文件及基本框架 三、接口實現 1、對棧的初始化 2、棧的銷毀 3、入棧操作 4、出棧操作 5、判斷棧是否為空 6、返回棧頂元素 7、遍歷棧 四、有效的括號 - 力扣&#xff08;LeetCode&#xff09; 題目描述&#xff1a; 思路&#xff…

靜態網頁和動態網頁區別

1&#xff0c;靜態網頁和動態網頁有何區別 1) 更新和維護 靜態網頁內容一經發布到網站服務器上&#xff0c;無論是否有用戶訪問&#xff0c;這些網頁內容都是保存在網站服務器上的。如果要修改網頁的內容&#xff0c;就必須修改其源文件&#xff0c;然后重新上傳到服務器上。…

k8s-----集群調度

目錄 一&#xff1a;調度約束 二&#xff1a;Pod 啟動創建過程 三&#xff1a;k8s調度過程 1、Predicate 有一系列的常見的算法 2、常見優先級選項 3、指定調度節點 &#xff08;1&#xff09;nodeName指定 &#xff08;2&#xff09;nodeSelector指定 四&#xff1a;親和…

【SA8295P 源碼分析】68 - Android 側用戶層 輸入子系統獲取 /dev/input/event0 節點數據 代碼流程分析

【SA8295P 源碼分析】68 - Android 側用戶層 輸入子系統獲取 /dev/input/event0 節點數據 代碼流程分析 一、EventHub.cpp 監聽 /dev/input/event0 節點流程二、EventHub.cpp 讀取 /dev/input/event0 節點數據流程系列文章匯總見:《【SA8295P 源碼分析】00 - 系列文章鏈接匯總…

C++——繼承

文章目錄 &#x1f99c;1. 什么是繼承&#x1f40a;1.1 概念&#x1f40a;1.2 格式&#x1f40a;1.3 繼承方式 & 訪問限定符 &#x1f426;2. 派生類和基類的賦值問題&#x1f9a9;3. 派生類和基類同名成員問題&#x1f413;4.派生類默認成員函數&#x1f409;4.1 構造函數…

React源碼解析18(1)------ React.createElement 和 jsx

1.React.createElement 我們知道在React17版本之前&#xff0c;我們在項目中是一定需要引入react的。 import React from “react” 即便我們有時候沒有使用到React&#xff0c;也需要引入。原因是什么呢&#xff1f; 在React項目中&#xff0c;如果我們使用了模板語法JSX&am…

使用OkHttp發送POST請求的幾種方式

使用OkHttp發送POST請求的幾種方式 介紹pom依賴基本的POST請求帶授權的POST請求POST方式發送JSON數據Multipart POST 請求 介紹 本文將介紹 OkHttp 客戶端的基本用法。 主要介紹 OkHttp 3.x 版本中發送Post請求的幾種方式。 pom依賴 <dependency><groupId>com.sq…

單調遞增的數字——力扣738

文章目錄 題目描述解法題目描述 解法 #include<iostream> #include<string>using namespace std;int monotoneIncreasingDigits

【學習】若依源碼(前后端分離版)之 “ 異常處理”

大型紀錄片&#xff1a;學習若依源碼&#xff08;前后端分離版&#xff09;之 “ 異常處理” 前言1、統一返回實體定義2、定義登錄異常定義3、基于ControllerAdvice注解的Controller層的全局異常統一處理4、測試訪問請求結語 前言 通常一個web框架中&#xff0c;有大量需要處理…

中小企業項目管理軟件推薦:選擇適合的工具提升項目效率!

中小企業項目管理軟件有哪些&#xff1f;Zoho Projects是一款好用無廣告的項目管理軟件。當個小創業者是真的不容易&#xff0c;不僅要管理團隊&#xff0c;還要管理團隊項目。很多團隊之前用了好多項目管理的軟件&#xff0c;但是都不太滿意。但是如果你經常參加創業者聚會上&…

常見的路由協議之RIP協議與OSPF協議

目錄 RIP OSPF 洪泛和廣播的區別 路由協議是用于在網絡中確定最佳路徑的一組規則。它們主要用于在路由器之間交換路由信息&#xff0c;以便找到從源到目標的最佳路徑。 常見的路由協議&#xff1a; RIP (Routing Information Protocol)&#xff1a;RIP 是一種基于距離向量算…

Mac os 上的apt-get install 就是brew install

Mac os 上面不支持apt-get install ,但是有個 brew install可以代替。 Homebrew是Mac OS的包管理器&#xff0c;可以方便地安裝各種需要的軟件。 1.1 安裝Homebrew 如果沒有安裝Homebrew&#xff0c;需要在終端輸入以下命令進行安裝&#xff1a; /usr/bin/ruby -e "$(…

使用wxPython和PyMuPDF在Python中顯示PDF目錄的實現

展示如何使用wxPython和PyMuPDF庫在Python中選擇PDF文件并將目錄顯示在列表框中。 簡介&#xff1a; 在本篇教程中&#xff0c;我們將學習如何使用wxPython和PyMuPDF庫在Python中選擇PDF文件&#xff0c;并將其目錄顯示在一個列表框中。這將使用戶能夠方便地瀏覽PDF文檔的目錄…