
2026-06-04:删除子数组后的最终元素。用go语言,给定一个整数数组 nums,共有两名玩家:Alice 和 Bob,并且 Alice 先手。
游戏会一直轮流进行,直到最后数组中只剩下 1 个元素。
在每一回合中,当前玩家从当前数组中选取一个连续的非空片段 nums[l..r],要求该片段长度严格小于当前数组长度 m(也就是不能把整个数组都选走)。一旦选中了这个片段,就把它从数组中删除,其余部分(左边和右边的元素)会首尾拼接,形成一个新的数组,继续下一回合。
当游戏结束时,数组只剩一个元素。Alice 试图让这个最终剩下的元素尽可能大,而 Bob 则试图让它尽可能小。双方都会采用最优策略。
你的任务是:在双方都最优的情况下,返回最后剩下的元素的值。
1 <= nums.length <= 100000。
1 <= nums[i] <= 100000。
输入: nums = [1,5,2]。
输出: 2。
解释:
一种有效的最优策略:
Alice 移除[1],数组变为[5, 2]。
Bob 移除[5],数组变为[2]。因此,答案是 2。
题目来自力扣3828。
初始数组:[1, 5, 2]
当前玩家:Alice(先手)
当前数组长度 m=3,Alice 只能删除长度1或2的连续片段(不能删整个数组)。
Alice的目标是让最终元素尽可能大,她需要预判Bob的后续操作,选择能锁定最大结果的删除方式:
[1](长度1)→ 剩余数组[5,2][5](长度1)→ 剩余数组[1,2][2](长度1)→ 剩余数组[1,5][1,5](长度2)→ 剩余数组[2][5,2](长度2)→ 剩余数组[1]Alice会排除对自己不利的方案:
[2]、方案5直接剩[1],最终结果固定,不是最优;[1,2],Bob会删2留1(最小化结果),最终是1;[1,5],Bob会删5留1,最终是1;[5,2],最终结果是2,是所有方案中最大的可能值。因此Alice最优操作:删除左侧片段[1]。
操作后新数组:[5, 2]
当前玩家:Bob(轮到后手)
当前数组长度 m=2,Bob 只能删除长度1的连续片段(不能删整个数组)。
Bob的目标是让最终元素尽可能小,他只有两种选择:
[5] → 剩余数组[2][2] → 剩余数组[5]Bob会选择让结果最小的方案:删除[5]。
操作后最终数组:[2]
数组仅剩1个元素,游戏终止。
最终结果:2。
这个游戏的核心结论不是模拟每一步操作,而是数学规律:
对应示例:数组首元素1,尾元素2,较小值是2,和游戏结果完全一致。
只需要执行两个操作:获取数组第一个元素、获取数组最后一个元素、比较大小。 这三个操作都是O(1) 常数时间操作,与数组长度无关。 因此:总时间复杂度 O(1)。
算法执行过程中,没有创建任何新的数组、集合、动态变量,仅使用了常数个临时变量存储首尾元素和结果。 因此:总额外空间复杂度 O(1)。
.
package main
import (
"fmt"
)
func finalElement(nums []int)int {
return max(nums[0], nums[len(nums)-1])
}
func main() {
nums := []int{1, 5, 2}
result := finalElement(nums)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
def final_element(nums):
return max(nums[0], nums[-1])
def main():
nums = [1, 5, 2]
result = final_element(nums)
print(result)
if __name__ == "__main__":
main()
.
#include <iostream>
#include <vector>
#include <algorithm>
int finalElement(const std::vector<int>& nums) {
return std::max(nums[0], nums[nums.size() - 1]);
}
int main() {
std::vector<int> nums = {1, 5, 2};
int result = finalElement(nums);
std::cout << result << std::endl;
return 0;
}
