LeetCode算法题(Go语言实现)_50

题目

现有一个包含所有正整数的集合 [1, 2, 3, 4, 5, …] 。
实现 SmallestInfiniteSet 类:
SmallestInfiniteSet() 初始化 SmallestInfiniteSet 对象以包含 所有 正整数。
int popSmallest() 移除 并返回该无限集中的最小整数。
void addBack(int num) 如果正整数 num 不 存在于无限集中,则将一个 num 添加 到该无限集中。

一、代码实现(堆与集合结合)


import (
	"container/heap"
)

// 定义最小堆类型
type IntHeap []int

func (h IntHeap) Len() int           { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *IntHeap) Push(x interface{}) {
	*h = append(*h, x.(int))
}

func (h *IntHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

// SmallestInfiniteSet 结构体定义
type SmallestInfiniteSet struct {
	currentMin int       // 当前连续整数起点
	heap       *IntHeap  // 存储被添加回的小值
	addedSet   map[int]bool // 记录已添加元素
}

// 构造函数初始化
func Constructor() SmallestInfiniteSet {
	h := &IntHeap{}
	heap.Init(h)
	return SmallestInfiniteSet{
		currentMin: 1,
		heap:       h,
		addedSet:   make(map[int]bool),
	}
}

// 弹出最小元素
func (this *SmallestInfiniteSet) PopSmallest() int {
	// 优先弹出已添加的最小元素
	if this.heap.Len() > 0 {
		smallest := heap.Pop(this.heap).(int)
		delete(this.addedSet, smallest)
		return smallest
	}
	// 弹出当前连续最小值并递增
	res := this.currentMin
	this.currentMin++
	return res
}

// 添加元素回集合
func (this *SmallestInfiniteSet) AddBack(num int) {
	// 只处理比当前连续最小值小且未被添加过的数
	if num < this.currentMin && !this.addedSet[num] {
		heap.Push(this.heap, num)
		this.addedSet[num] = true
	}
}

/**
 * 使用示例:
 * obj := Constructor();
 * param_1 := obj.PopSmallest();
 * obj.AddBack(num);
 */

二、算法分析

1. 核心思路
  • 双轨存储:用current_min表示连续整数起点,堆存储被添加回的小值
  • 最小优先:始终优先弹出被添加回的最小值,保证顺序正确性
  • 去重机制:通过集合维护已添加元素,避免重复入堆
2. 关键步骤
  1. 初始化阶段

    • current_min初始化为1,表示当前连续整数起点
    • 创建空堆added_heap和集合added_set
  2. 弹出操作

    • 优先检查堆中是否有被添加回的小值
    • 若堆为空则弹出当前current_min并递增
  3. 添加操作

    • 仅当数值小于当前连续起点且未被添加过时入堆
    • 同时更新堆和集合保证数据一致性
3. 复杂度
操作 时间复杂度 说明
popSmallest O(log n) 堆操作主导
addBack O(log n) 堆插入与集合查询共同作用

三、图解示例

LeetCode算法题(Go语言实现)_50_第1张图片

四、边界条件与扩展

1. 特殊场景验证
  • 连续弹出后添加:验证数值重新进入堆的逻辑
  • 添加大数值:确认不会影响current_min
  • 重复添加:确保集合去重机制有效
2. 扩展应用
  • 动态阈值调整:current_min可扩展为区间管理
  • 批量操作优化:支持批量添加/弹出操作
  • 持久化存储:增加序列化/反序列化功能
3. 多语言实现
import heapq

class SmallestInfiniteSet:
    def __init__(self):
        self.current_min = 1
        self.added_heap = []
        # 维护已添加的且小于current_min的元素的最小堆
        self.added_set = set()      
        # 避免重复添加元素
    
    def popSmallest(self) -> int:
        if self.added_heap:
            smallest = heapq.heappop(self.added_heap)
            self.added_set.remove(smallest)
            return smallest
        else:
            res = self.current_min
            self.current_min += 1
            return res
    
    def addBack(self, num: int) -> None:
        if num < self.current_min and num not in self.added_set:
            heapq.heappush(self.added_heap, num)
            self.added_set.add(num)
import java.util.PriorityQueue;
import java.util.HashSet;

class SmallestInfiniteSet {
    private int currentMin;
    private PriorityQueue<Integer> addedHeap;
    private HashSet<Integer> addedSet;

    public SmallestInfiniteSet() {
        currentMin = 1;
        addedHeap = new PriorityQueue<>();
        addedSet = new HashSet<>();
    }
    
    public int popSmallest() {
        if (!addedHeap.isEmpty()) {
            int smallest = addedHeap.poll();
            addedSet.remove(smallest);
            return smallest;
        }
        return currentMin++;
    }
    
    public void addBack(int num) {
        if (num < currentMin && !addedSet.contains(num)) {
            addedHeap.offer(num);
            addedSet.add(num);
        }
    }
}
class SmallestInfiniteSet {
    constructor() {
        this.currentMin = 1;
        this.addedHeap = [];
        this.addedSet = new Set();
    }

    popSmallest() {
        if (this.addedHeap.length > 0) {
            const smallest = this.addedHeap.shift();
            this.addedSet.delete(smallest);
            return smallest;
        }
        return this.currentMin++;
    }

    addBack(num) {
        if (num < this.currentMin && !this.addedSet.has(num)) {
            this.addedSet.add(num);
            this.addedHeap.push(num);
            this.addedHeap.sort((a,b) => a-b);
        }
    }
}

五、总结与优化

1. 算法对比
方法 优势 适用场景
堆+集合 动态维护高效 频繁添加/弹出操作
纯集合遍历 实现简单 低频操作场景
平衡树 查询删除统一复杂度 需要范围查询
2. 工程优化
  • 堆排序优化:使用更高效堆实现(如斐波那契堆)
  • 内存压缩:对连续区间采用位图标记
  • 延迟更新:批量处理current_min递增
3. 扩展方向
  • 区间合并:记录多个连续区间段
  • 多线程安全:添加同步锁机制
  • 历史记录:支持撤销操作功能

你可能感兴趣的:(LeetCode,算法,leetcode,golang)