2106. 摘水果,梳理思路

文章目錄

    • 題目概要
    • java 解法
    • 詳解

在這里插入圖片描述

題目概要

在一個無限的 x 坐標軸上,有許多水果分布在其中某些位置。給你一個二維整數數組 fruits ,其中 fruits[i] = [positioni, amounti] 表示共有 amounti 個水果放置在 positioni 上。fruits 已經按 positioni 升序排列 ,每個 positioni 互不相同 。

另給你兩個整數 startPos 和 k 。最初,你位于 startPos 。從任何位置,你可以選擇 向左或者向右 走。在 x 軸上每移動 一個單位 ,就記作 一步 。你總共可以走 最多 k 步。你每達到一個位置,都會摘掉全部的水果,水果也將從該位置消失(不會再生)。

返回你可以摘到水果的 最大總數 。

示例 1:
在這里插入圖片描述

輸入:fruits = [[2,8],[6,3],[8,6]], startPos = 5, k = 4
輸出:9
解釋:
最佳路線為:

  • 向右移動到位置 6 ,摘到 3 個水果
  • 向右移動到位置 8 ,摘到 6 個水果
    移動 3 步,共摘到 3 + 6 = 9 個水果

示例 2:
在這里插入圖片描述

輸入:fruits = [[0,9],[4,1],[5,7],[6,2],[7,4],[10,9]], startPos = 5, k = 4
輸出:14
解釋:
可以移動最多 k = 4 步,所以無法到達位置 0 和位置 10 。
最佳路線為:

  • 在初始位置 5 ,摘到 7 個水果
  • 向左移動到位置 4 ,摘到 1 個水果
  • 向右移動到位置 6 ,摘到 2 個水果
  • 向右移動到位置 7 ,摘到 4 個水果
    移動 1 + 3 = 4 步,共摘到 7 + 1 + 2 + 4 = 14 個水果

示例 3:

在這里插入圖片描述

輸入:fruits = [[0,3],[6,4],[8,5]], startPos = 3, k = 2
輸出:0
解釋:
最多可以移動 k = 2 步,無法到達任一有水果的地方

提示:
1<=fruits.length<=105fruits[i].length==20<=startPos,positioni<=2?105對于任意i>0,positioni?1<positioni均成立(下標從0開始計數)1<=amounti<=1040<=k<=2?1051 <= fruits.length <= 10^5 \\ fruits[i].length == 2\\ 0 <= startPos, positioni <= 2 * 10^5 \\ 對于任意 i > 0 ,positioni-1 < positioni 均成立(下標從 0 開始計數)\\ 1 <= amounti <= 10^4 \\ 0 <= k <= 2 * 10^5 1<=fruits.length<=105fruits[i].length==20<=startPos,positioni<=2?105對于任意i>0positioni?1<positioni均成立(下標從0開始計數)1<=amounti<=1040<=k<=2?105

java 解法

public int maxTotalFruits(int[][] fruits, int startPos, int k) {int n = fruits.length;// 提取位置和數量,方便操作int[] positions = new int[n];int[] amounts = new int[n];for (int i = 0; i < n; i++) {positions[i] = fruits[i][0];  // 位置amounts[i] = fruits[i][1];    // 水果數量}// 前綴和數組:prefix[i] 表示前 i 個位置的水果總數int[] prefix = new int[n + 1];for (int i = 0; i < n; i++) {prefix[i + 1] = prefix[i] + amounts[i];}int maxFruits = 0;  // 記錄能摘到的最大水果數int left = 0;       // 滑動窗口的左指針// 滑動窗口:右指針 right 從 0 到 n-1for (int right = 0; right < n; right++) {// 當前嘗試的區間是 [left, right]int L = positions[left];      // 區間最左位置int R = positions[right];     // 區間最右位置// 計算從 startPos 出發,走完 [L, R] 所需的最少步數int steps = calculateSteps(startPos, L, R);// 如果步數超過了 k,說明走太遠了,需要縮小窗口(移動 left)while (left <= right && steps > k) {left++;  // 縮小左邊界if (left > right) break;L = positions[left];R = positions[right];steps = calculateSteps(startPos, L, R);}// 如果當前窗口有效,更新最大水果數if (left <= right) {int total = prefix[right + 1] - prefix[left];  // [left, right] 的水果總數maxFruits = Math.max(maxFruits, total);}}return maxFruits;
}// 計算從 startPos 出發,走完區間 [L, R] 所需的最少步數
private int calculateSteps(int startPos, int L, int R) {if (R <= startPos) {// 所有水果都在起點或左邊:只向左走return startPos - L;} else if (L >= startPos) {// 所有水果都在起點或右邊:只向右走return R - startPos;} else {// 水果分布在起點兩側// 方案1:先向左走到 L,再向右走到 Rint goLeftFirst = (startPos - L) * 2 + (R - startPos);// 方案2:先向右走到 R,再向左走到 Lint goRightFirst = (R - startPos) * 2 + (startPos - L);// 返回兩種方案中步數更少的那個return Math.min(goLeftFirst, goRightFirst);}
}public static void main(String[] args) {Solution1 solution = new Solution1();// 示例 1int[][] fruits1 = {{2,8},{6,3},{8,6}};System.out.println(solution.maxTotalFruits(fruits1, 5, 4)); // 輸出: 9// 示例 2int[][] fruits2 = {{0,9},{4,1},{5,7},{6,2},{7,4},{10,9}};System.out.println(solution.maxTotalFruits(fruits2, 5, 4)); // 輸出: 14// 示例 3int[][] fruits3 = {{0,3},{6,4},{8,5}};System.out.println(solution.maxTotalFruits(fruits3, 3, 2)); // 輸出: 0
}

詳解

目的:將二維信息解耦為兩個一維數組,便于后續使用雙指針、二分查找等操作。

int n = fruits.length;// 提取位置和數量,方便操作
int[] positions = new int[n];
int[] amounts = new int[n];
for (int i = 0; i < n; i++) {positions[i] = fruits[i][0];  // 位置amounts[i] = fruits[i][1];    // 水果數量
}

前綴和(Prefix Sum)用來快速計算總和的一種方式
第 i+1 個累計值 = 第 i 個累計值 + 第 i 個位置的水果數

// 前綴和數組:prefix[i] 表示前 i 個位置的水果總數
int[] prefix = new int[n + 1];
for (int i = 0; i < n; i++) {prefix[i + 1] = prefix[i] + amounts[i];
}

拿示例 1: 舉例
fruits = [[2,8], [6,3], [8,6]]
最終前綴和數組

prefix[i]含義對應的水果
prefix[0] = 0前 0 個位置的水果總數什么都沒有
prefix[1] = 8前 1 個位置的水果總數位置 2:8 個
prefix[2] = 11前 2 個位置的水果總數位置 2+6:8+3=11
prefix[3] = 17前 3 個位置的水果總數位置 2+6+8:8+3+6=17

用前綴和快速算“某段區間的水果總數
🌰 例子 1:只摘位置 6 的水果(第 1 個位置)

  • left = 1, right = 1
  • 總數 = prefix[right+1] - prefix[left] = prefix[2] - prefix[1] = 11 - 8 = 3 ?

🌰 例子 2:摘位置 6 和 8 的水果(第 1 和第 2 個位置)

  • left = 1, right = 2
  • 總數 = prefix[3] - prefix[1] = 17 - 8 = 9 ?
    也就是 3 + 6 = 9

🌰 例子 3:摘所有水果(第 0 到第 2 個位置)

  • left = 0, right = 2
  • 總數 = prefix[3] - prefix[0] = 17 - 0 = 17 ?

🌰 例子 4:只摘位置 2 的水果(第 0 個位置)

  • left = 0, right = 0
  • 總數 = prefix[1] - prefix[0] = 8 - 0 = 8
    這在滑動窗口中特別有用,因為 right 每移動一次,都要算一次區間和。

從左向右,滑動窗口
我們要在最多走 k 步的前提下,從起點 startPos 出發,摘到最多的水果。
maxFruits:就像一個“最高分記錄”,通過 在 合理的 k 步條件下獲取的最多水果數
外層循環:右指針 right 不斷向右擴展
right 從 0 開始,一步步向右移動(0 → 1 → 2 → …)
每次 right 向右一格,就相當于我們想多摘一個位置的水果

for (int right = 0; right < n; right++) {

當前嘗試的區間 [left, right]
拿示例 1: 舉例
fruits = [[2,8], [6,3], [8,6]]
positions = [2, 6, 8]
那么 以下就會從

rightleft區間步數是否可達水果數maxFruits
00[2]3?88
10[2,6]5? → left=1--
1[6]1?3max(8,3)=8
21[6,8]3?9max(8,9)=9
int L = positions[left];      // 區間最左位置
int R = positions[right];     // 區間最右位置

計算區間區間步數
計算走完這個區間需要多少步
left <= right 縮小空間,保持空間合法性
steps > k 步數超過k步后,進入 while 調整左側空間,使步數減少,
while (left <= right && steps > k)while 發現 septs 直到 空間合法后跳出循環

// 計算從 startPos 出發,走完 [L, R] 所需的最少步數
int steps = calculateSteps(startPos, L, R);// 如果步數超過了 k,說明走太遠了,需要縮小窗口(移動 left)
while (left <= right && steps > k) {left++;  // 縮小左邊界if (left > right) break;L = positions[left];R = positions[right];steps = calculateSteps(startPos, L, R);
}

校驗合法性,并更新水果數
prefix[right + 1] - prefix[left] 這邊用到了上面 所寫的 前綴和 計算累計數量, left 跟 right 是 對應的坐標點,由于前綴和 第一個坐標點為 0 所以需要加1

prefix[i]含義對應的水果
prefix[0] = 0前 0 個位置的水果總數什么都沒有
prefix[1] = 8前 1 個位置的水果總數位置 2:8 個
prefix[2] = 11前 2 個位置的水果總數位置 2+6:8+3=11
prefix[3] = 17前 3 個位置的水果總數位置 2+6+8:8+3+6=17

right + 1 前 right+1 個數的總和
left 前 left 個數的總和

amounts:     [ 8 ,  3 ,  6 ]↑    ↑    ↑
索引:         0    1    2prefix:  [0,  8,  11,  17]↑   ↑   ↑    ↑0   1   2    3

繼續用示例1
fruits = [[2,8],[6,3],[8,6]]
比如 :獲取 位置為6 的 水果, 由于 前綴和的緣故 第一個是固定值,后面的值是累加過來的
prefix[right + 1] - prefix[left] = prefix[2] - prefix[1] = 11 - 8 = 3
Math.max 對比 兩數大小

// 如果當前窗口有效,更新最大水果數
if (left <= right) {int total = prefix[right + 1] - prefix[left];  // [left, right] 的水果總數maxFruits = Math.max(maxFruits, total);
}

計算步數
R <= startPos 從步數左側走完的步數, 上面 for 循環 R 是在一步步從左走到右側的
L >= startPos 從右側走完的步數,L 因為上面空間縮小調整一步步走到右側
獲取 在 R 大于起始步數并 L 還沒移動到右側時 獲取 中間的兩種狀態
(startPos - L) * 2 + (R - startPos) 先向左走到 L,再向右走到 R
(R - startPos) * 2 + (startPos - L) 先先向右走到 R,再向左走到 L
Math.min 獲取兩者最小步數方案,可能起始位置并不居中,導致 往回走步數減少減少的情況

// 計算從 startPos 出發,走完區間 [L, R] 所需的最少步數
private int calculateSteps(int startPos, int L, int R) {if (R <= startPos) {// 所有水果都在起點或左邊:只向左走return startPos - L;} else if (L >= startPos) {// 所有水果都在起點或右邊:只向右走return R - startPos;} else {// 水果分布在起點兩側// 方案1:先向左走到 L,再向右走到 Rint goLeftFirst = (startPos - L) * 2 + (R - startPos);// 方案2:先向右走到 R,再向左走到 Lint goRightFirst = (R - startPos) * 2 + (startPos - L);// 返回兩種方案中步數更少的那個return Math.min(goLeftFirst, goRightFirst);}
}

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

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

相關文章

深入理解消息隊列(MQ)核心原理與設計精髓

引言&#xff1a;從一個“不堪重負”的訂單系統說起想象一個簡化的電商下單流程&#xff1a;用戶點擊“下單”后&#xff0c;系統需要&#xff1a;在訂單數據庫中創建一條記錄。調用庫存服務&#xff0c;扣減商品庫存。調用營銷服務&#xff0c;給用戶發放積分和優惠券。調用通…

前端手撕題總結篇(算法篇——來自Leetcode牛客)

鏈表指定區域反轉 找到區間&#xff08;頭和為 for循環當**時&#xff09;->反轉鏈表&#xff08;返回反轉過后的頭和尾&#xff09;->連接 function reverseBetween( head , m , n ) {//preEnd&cur&nextStart cur.next斷開if(mn)return head;const vHeadNode…

從Excel到工時管理系統:企業如何選擇更高效的工時記錄工具?

還在為手工統計員工工時而頭疼嗎&#xff1f;月末堆積如山的Excel表格、反復核對的數據、層出不窮的差錯&#xff0c;這些問題正在拖慢企業的發展步伐。8Manage工時管理系統發現&#xff0c;傳統手工記錄不僅耗費大量人力&#xff0c;更讓寶貴的工時數據難以轉化為有效的管理決…

Java設計模式之《命令模式》

目錄 1、介紹 1.1、命令模式定義 1.2、對比 1.3、典型應用場景 2、命令模式的結構 2.1、組成部分&#xff1a; 2.2、整體流程 3、實現 3.1、沒有命令模式 3.2、命令模式寫法 4、命令模式的優缺點 前言 java設計模式分類&#xff1a; 1、介紹 1.1、命令模式定義 命…

【動態規劃算法】路徑問題

什么是動態規劃算法動態規劃&#xff08;Dynamic Programming&#xff0c;簡稱 DP&#xff09;是一種通過分解復雜問題為重疊子問題&#xff0c;并存儲子問題的解以避免重復計算&#xff0c;從而高效求解具有特定性質&#xff08;重疊子問題、最優子結構&#xff09;問題的算法…

Java基本技術講解

一、基礎語法三要素 暫時無法在飛書文檔外展示此內容 &#x1f511; 黃金法則?&#xff1a;每個變量都要聲明類型&#xff01;二、程序邏輯控制&#xff08;游戲行為核心&#xff09; 條件判斷&#xff1a;if-else - “岔路口選擇” // 撿到金幣邏輯 if (isTouching(Coin.clas…

【網絡基礎2】路由器的 “兩扇門”:二層接口和三層接口到底有啥不一樣?

目錄 前言:路由器不是只有 “插網線的口” 一、先搞懂一個基礎:路由器是 “網絡交通樞紐” 二、二層接口:“小區內部的單元門”,只認 “住戶身份證” 1. 啥是二層接口? 2. 用 “小區內部串門” 理解二層接口 步驟 1:手機打包數據,寫上 “收件人身份證” 步驟 2:二…

MLIR TableGen

簡介 TableGen 是一種領域特定語言&#xff08;DSL&#xff09;&#xff0c;TableGen 的設計目標是允許編寫靈活的描述&#xff0c;并將記錄的通用特性提取出來&#xff0c;從而減少重復代碼并提高代碼的可維護性。 TableGen的工作流程&#xff1a; 前端解析&#xff1a; Ta…

2、docker容器命令 | 信息查看

1、命令總覽命令作用docker ps查看運行中的容器&#xff08;-a查看所有容器&#xff09;docker logs [CONTAINER]查看容器日志&#xff08;-f實時追蹤日志&#xff09;docker inspect [CONTAINER]查看容器詳細信息&#xff08;JSON格式&#xff09;docker stats [CONTAINER]實時…

【MySQL】MySQL中鎖有哪些?

一、按照粒度分類&#xff1a; 粒度越小&#xff0c;并發度越高&#xff0c;鎖開銷越大。 1.全局鎖&#xff1a; 作用&#xff1a; 鎖定整個MySQL實例(所有數據庫)。適用場景&#xff1a; 全庫邏輯部分。(確保備份期間數據的一致性。)實現方式&#xff1a; 通過 FLUSH TABLES W…

語義分割--deeplabV3+

根據論文網絡結構圖講一下&#xff1a;網絡分為兩部分&#xff1a;encoder和decoder部分。 Encoder&#xff1a;DCNN就是主干網絡&#xff0c;例如resnet&#xff0c;Xception&#xff0c;MobileNet這些&#xff08;主干網絡也要使用空洞卷積&#xff09;&#xff0c;對dcnn的結…

Azure DevOps 中的代理

必知詞匯 深入研究 Azure DevOps 中的代理之前需要掌握的基本概念: 代理:Azure DevOps 中的代理是一個軟件組件,負責執行流水線中的任務和作業。這可能包括數據中心內的物理服務器、本地或云端托管的虛擬機,甚至是容器化環境。這些代理可以在各種操作系統和環境中運行,例如…

AUTOSAR進階圖解==>AUTOSAR_SRS_ADCDriver

AUTOSAR ADC驅動詳解 基于AUTOSAR標準的ADC驅動模塊需求規范分析目錄 ADC驅動模塊概述 關鍵概念定義 ADC驅動架構 ADC驅動在AUTOSAR分層架構中的位置ADC驅動的主要職責 ADC驅動配置結構 通用配置(AdcGeneral)硬件單元配置(AdcHwUnit)通道配置(AdcChannel)通道組配置(AdcChanne…

寶馬集團與SAP聯合打造生產物流數字化新標桿

在德國雷根斯堡的寶馬工廠&#xff0c;每57秒就有一輛新車下線。這座工廠不僅是汽車制造的基地&#xff0c;更是寶馬集團向SAP S/4HANA云平臺轉型的先鋒項目。通過“RISE with SAP”計劃&#xff0c;寶馬將該工廠的運營系統全面遷移至SAP S/4HANA Cloud Private Edition&#x…

Go 語言實戰:構建一個高性能的 MySQL + Redis 應用

引言&#xff1a;為什么是 Go MySQL Redis&#xff1f;在現代后端技術棧中&#xff0c;Go MySQL Redis 的組合堪稱“黃金搭檔”&#xff0c;被廣泛應用于各種高并發業務場景。Go 語言&#xff1a;以其卓越的并發性能、簡潔的語法和高效的執行效率&#xff0c;成為構建高性能…

Excel超級處理器,多個word表格模板中內容提取到Excel表格中

在職場中&#xff0c;很多人習慣在word里插入表格&#xff0c;設計模板&#xff0c;填寫內容&#xff0c;一旦有多個word文件需要整理在excel表格中&#xff0c;最常見的工作方式就是每個word文件打開&#xff0c;復制&#xff0c;粘貼到excel表格里&#xff0c;這樣的工作方式…

前端工程化:ES6特性

本文為個人學習筆記整理&#xff0c;僅供交流參考&#xff0c;非專業教學資料&#xff0c;內容請自行甄別 文章目錄一、let與var1.1、越獄問題1.2、變量的重復聲明1.3、變量提升問題二、解構2.1、數組解構2.2、對象解構2.3、方法解構三、鏈判斷四、參數默認值五、箭頭函數六、模…

大屏項目展示

一、項目克隆與基礎操作 我們參考的項目 互聯網設備可視化平臺---IofTV-Screen: ??一個基于 vue、datav、Echart 框架的物聯網可視化(大屏展示)模板,提供數據動態刷新渲染、屏幕適應、數據滾動配置,內部圖表自由替換、Mixins注入等功能,持續更新.... 將次項目克隆到本…

基于R語言地理加權回歸、主成份分析、判別分析等空間異質性數據分析實踐技術應用

在自然和社會科學領域有大量與地理或空間有關的數據&#xff0c;這一類數據一般具有嚴重的空間異質性&#xff0c;而通常的統計學方法并不能處理空間異質性&#xff0c;因而對此類型的數據無能為力。以地理加權回歸為基礎的一系列方法&#xff1a;經典地理加權回歸&#xff0c;…

【Flask 基礎 ①】 | 路由、參數與模板渲染

0 序言 Flask 是 Python 生態中一款輕量級 Web 框架&#xff0c;以簡潔、靈活著稱。 學習 Flask 的意義在于&#xff1a; 快速開發&#xff1a;通過少量代碼即可搭建功能完整的 Web 應用&#xff1b;理解原理&#xff1a;其設計清晰體現了 Web 框架的核心邏輯&#xff0c;如路由…