基于数组的两类查询:区间三角形最大周长计算与元素更新
数组区间三角形最大周长查询与单点更新问题解决方案
嘿,我来帮你梳理这个问题的解法。我们的核心需求是处理一个数值数组,支持两种操作:一是查询指定区间内能构成三角形的三边的最大周长,二是更新数组中的某个元素值。先从你给出的示例入手,再展开讲高效的实现思路。
示例场景回顾
初始数组:a[] = [3, 1, 8, 9, 7]
4次操作流程:
- 区间查询(1,5):
这个区间覆盖了整个数组,元素是3、1、8、9、7。要找最大周长的三角形,优先看最大的几个数——8、9、7,它们满足三角形三边条件(任意两边之和大于第三边),所以周长是8+9+7=24,返回24。
- 单点更新:把索引2的元素改成12(这里要注意是1-based索引,对应0-based的话是索引1),更新后数组变成
a[] = [3, 12, 8, 9, 7]。 - 再次区间查询:
现在最大的三个数是12、9、8,检查12 < 9+8(17),满足条件,所以周长是12+9+8=29,这就是当前的最大周长。
- (你可以继续补充后续操作,比如再更新某个元素或者查询其他区间)
核心思路:为什么只需要关注最大的几个元素?
三角形的最大周长一定来自区间内最大的、能满足三边条件的三个数。道理很简单:假设我们有三个数x ≥ y ≥ z,如果x < y + z,那它们的和就是最大的可能周长,因为任何其他组合的和都不会超过x+y+z;如果这三个不满足,那更小的数组合的和只会更小,也没必要再看了。
实现方案选择
根据你的数据规模和操作频率,有两种方案可选:
- 简单方案(小数据/少操作):每次查询时直接提取区间元素,排序后从后往前验证三边条件。这种方法写起来快,但效率低——查询时间复杂度是O(n log n),更新是O(1)。
- 高效方案(大数据/多操作):用线段树来存储每个区间的前3大元素。这样查询时可以快速合并区间的前3大元素,更新时也只需修改对应节点的信息,查询和更新的时间复杂度都是O(log n),非常适合高频操作的场景。
高效方案的具体实现(Python示例)
下面是线段树的实现代码,每个节点保存对应区间的前3大元素:
class SegmentTreeNode: def __init__(self, start, end): self.start = start self.end = end self.left = None self.right = None self.top3 = [] # 降序存储区间内最大的3个元素 def build_segment_tree(arr, start, end): node = SegmentTreeNode(start, end) if start == end: node.top3 = [arr[start]] return node mid = (start + end) // 2 node.left = build_segment_tree(arr, start, mid) node.right = build_segment_tree(arr, mid + 1, end) # 合并左右子节点的top3,取最大的3个 merged = sorted(node.left.top3 + node.right.top3, reverse=True) node.top3 = merged[:3] return node def update_node(node, idx, val): if node.start == node.end == idx: node.top3 = [val] return mid = (node.start + node.end) // 2 if idx <= mid: update_node(node.left, idx, val) else: update_node(node.right, idx, val) # 更新当前节点的top3 merged = sorted(node.left.top3 + node.right.top3, reverse=True) node.top3 = merged[:3] def query_range(node, l, r): if node.end < l or node.start > r: return [] if l <= node.start and node.end <= r: return node.top3.copy() left_top = query_range(node.left, l, r) right_top = query_range(node.right, l, r) merged = sorted(left_top + right_top, reverse=True) return merged[:3] def calculate_max_perimeter(top3_list): sorted_nums = sorted(top3_list, reverse=True) if len(sorted_nums) < 3: return -1 # 无法构成三角形的标识 # 先验证最大的三个数 if sorted_nums[0] < sorted_nums[1] + sorted_nums[2]: return sum(sorted_nums[:3]) # 若前三个不满足,说明区间内没有能构成三角形的三元组 return -1 # 示例使用 original_arr = [3, 1, 8, 9, 7] root = build_segment_tree(original_arr, 0, len(original_arr)-1) # 第一次查询整个区间(对应示例的(1,5),1-based转0-based是0-4) top3 = query_range(root, 0, 4) print(calculate_max_perimeter(top3)) # 输出24 # 更新1-based索引2的元素为12(对应0-based索引1) update_node(root, 1, 12) top3_updated = query_range(root, 0, 4) print(calculate_max_perimeter(top3_updated)) # 输出29
注意点
- 索引问题:一定要区分清楚题目中是1-based还是0-based索引,代码里用的是0-based,实际使用时要对应调整。
- 边界情况:如果区间内元素不足3个,或者所有三元组都不满足三边条件,记得返回一个明确的标识(比如代码里的-1),表示无法构成三角形。
内容的提问来源于stack exchange,提问作者John Simmons
相关产品推荐
相关产品推荐

