一個有名的按摩師會收到源源不斷的預約請求,每個預約都可以選擇接或不接。在每次預約服務之間要有休息時間,是以她不能接受相鄰的預約。給定一個預約請求序列,替按摩師找到最優的預約集合(總預約時間最長),傳回總的分鐘數。
注意:本題相對原題稍作改動
示例 1:輸入: [1,2,3,1] 輸出: 4
解釋: 選擇 1 号預約和 3 号預約,總時長 = 1 + 3 = 4。
作者:FlagMain
連結:https://leetcode-cn.com/problems/the-masseuse-lcci/solution/1716-an-mo-shi-phpdong-tai-gui-hua-jie-jue-gun-don/
解題思路
動态規劃解決
把每次處理的目前元素當成最後一個元素處理。目前元素前一位的處理結果已知,隻需要判斷目前處理規則 加前一次已知結果
每次處理有兩種可能,這次接受 和 這次不接受
是以設定記錄每次處理的兩種結果 $dp[i][0]不接受 和 $dp[i][1]接受 來代表兩種情況選擇的總數
$dp[i][0]不接受 那上次肯定沒有接受預約或上次接受了預約 是以我們取值為 已知的 上次處理兩種情況的最大值
$dp[i][1]接受 那上次肯定沒有接受預約 是以取值為 已知的 上次處理沒有接受預約的結果
初始化第1天的選擇結果
$dp[0][0] = 0; //下标為 i 的這一天不接受預約的最大時長
$dp[0][1] = $nums[0]; //下标為 i 的這一天接受預約的最大時長
// 第二行 -- 左面是不選擇(取上一次結果中最大值),右面是選擇(選擇上次結果左邊值)
// 1, 2, 3, 1
// 0 1 1 2 2 4 4 3
// 1 2 4 4
// 優化後方法 massage3()
class Solution {
/**
* @param $nums
* @return int|mixed
*/
function massage($nums) {
// 時間複雜度 O(n)
// 空間複雜度 O(2n)
$count = count($nums);
if ( $count == 0 ) return 0;
if ( $count == 1 ) return $nums[0];
// 初始化第1天
$dp[0][0] = 0; //第一天 如果不接受 那就是0
$dp[0][1] = $nums[0]; //第一天 如果接受 那就是第一個元素值
// 第一天情況已經分别已知,去處理剩餘
for ($i = 1; $i < $count; $i++) {
//不接受:上次沒有接受預約,或上次接受了預約。取最大值即:max($dp[$i - 1][0], $dp[$i - 1][1]);
$dp[$i][0] = max($dp[$i - 1][0], $dp[$i - 1][1]);
//接受:上次肯定沒有接受預約,加上這次的值即:dp[i - 1][0] + nums[i]
$dp[$i][1] = $dp[$i - 1][0] + $nums[$i];
}
// 傳回最終結果的最大值
return max($dp[$count - 1][0], $dp[$count - 1][1]);
}
// -----------------------------------------------------------------------
// 優化 function massage()
// 根據massage()基于二維數組的處理 優化為一維數組的處理 優化空間複雜度 O(n)
// 目前處理的結果是 上次的結果值 和 上上次的結果值加上目前值 的最大值
function massage2($nums) {
$count = count($nums);
if ( $count == 0 ) return 0;
if ( $count == 1 ) return $nums[0];
// 設定前兩次的最大結果
$dp[0] = $nums[0];
$dp[1] = max($nums[0],$nums[1]);
// 處理剩餘
for ($i = 2; $i < $count; $i++) {
// 上次的結果值 和 上上次的結果值加上目前值 的最大值
$dp[$i] = max($dp[$i - 1], $dp[$i - 2] + $nums[$i]);
}
return array_pop($dp);
}
// -----------------------------------------------------------------------
// 優化 function massage()
// 滾動變量處理 優化空間複雜度 O(1)
function massage3($nums) {
$count = count($nums);
if ( $count == 0 ) return 0;
if ( $count == 1 ) return $nums[0];
// 設定第一次各情況值
$a = 0;
$b = $nums[0];
// 處理剩餘
for ($i = 1; $i < $count; $i++) {
// 獲得不選擇時 最優結果
$tmp1 = $a > $b ? $a : $b;
// 擷取選擇時 結果
$tmp2 = $a + $nums[$i];
$a = $tmp1;
$b = $tmp2;
}
// 傳回最優值
return $a > $b ? $a : $b;
}
}
$arr = [1,2,3,1];
$arr = [2,1,4,5,3,1,1,3];
print_r( (new Solution())->massage( $arr ) );