在计算 a^n 时,传统方法需执行 n 次乘法,而快速幂通过二分思想将复杂度优化至 O(log n)。以下是 Go 语言实现:
// FastPow 计算 base^exp 对 mod 取模的结果
func FastPow(base, exp, mod int) int {
result := 1
for exp > 0 {
if exp%2 == 1 { // 若指数为奇数,将当前底数乘入结果
result = (result * base) % mod
}
base = (base * base) % mod // 底数平方
exp /= 2 // 指数减半
}
return result
}
// 使用切片映射存储有向图
type Graph struct {
vertices int
adjList map[int][]Edge
}
type Edge struct {
to int
weight int
}
func (g *Graph) AddEdge(from, to, weight int) {
g.adjList[from] = append(g.adjList[from], Edge{to, weight})
}
// 伪代码示例:词频统计
public void map(LongWritable key, Text value) {
String[] words = value.toString().split(" ");
for (String word : words) {
output.collect(new Text(word), new IntWritable(1));
}
}
public void reduce(Text key, Iterable<IntWritable> values) {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
output.collect(key, new IntWritable(sum));
}
def two_sum_brute_force(nums, target):
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
return []
时间复杂度为 O(n²),适用于小规模数据,无需额外空间。
哈希表优化解法
利用字典存储数值与索引的映射,单次遍历即可完成匹配。
def two_sum_hash(nums, target):
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []
该方法将时间复杂度降至 O(n),空间复杂度为 O(n),是时间和效率的平衡选择。
性能对比
方法
时间复杂度
空间复杂度
暴力枚举
O(n²)
O(1)
哈希表
O(n)
O(n)
4.2 接雨水问题的单调栈与双指针实现
问题核心与解法思路
接雨水问题是典型的数组类难题,目标是计算 n 个非负整数表示的柱状图中能接多少单位的雨水。关键在于每个位置能承载的水量由其左右两侧最高柱子的最小值决定。
双指针法实现
利用左右双指针向中间收敛,维护左右最大值。当左最大小于右最大时,左侧瓶颈确定,可直接计算积水。
func trap(height []int) int {
left, right := 0, len(height)-1
maxLeft, maxRight := 0, 0
water := 0
for left < right {
if height[left] < height[right] {
if height[left] >= maxLeft {
maxLeft = height[left]
} else {
water += maxLeft - height[left]
}
left++
} else {
if height[right] >= maxRight {
maxRight = height[right]
} else {
water += maxRight - height[right]
}
right--
}
}
return water
}
func lengthOfLIS(nums []int) int {
tails := []int{}
for _, num := range nums {
left, right := 0, len(tails)
for left < right {
mid := (left + right) / 2
if tails[mid] < num {
left = mid + 1
} else {
right = mid
}
}
if left == len(tails) {
tails = append(tails, num)
} else {
tails[left] = num
}
}
return len(tails)
}
上述代码中,left 通过二分法确定 num 在 tails 中的插入点,替换或扩展数组。最终 tails 长度即为 LIS 长度。