leetcode-go-04
leetcode热题100-GO解-2025.3.23
15/100
今日主要在忙双选会事宜,毕竟号称本校春招最大规模双选会
累一天但是每日日常不能断
53.最大子数组和
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组是数组中的一个连续部分。
示例 1:
1 | 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] |
示例 2:
1 | 输入:nums = [1] |
示例 3:
1 | 输入:nums = [5,4,-1,7,8] |
很经典的基础题,这里用动态规划方式来解
Kadane算法
1 | func maxSubArray(nums []int) int { |
Kadane算法的核心在于它采用了动态规划的思想,通过一次遍历数组,同时维护两个变量:
- 当前最大子数组和(
currentMax
):表示以当前元素结尾的最大子数组和。 - 全局最大子数组和(
globalMax
):表示整个数组中找到的最大子数组和。
在遍历数组的过程中,对于每个元素,算法会根据以下规则更新这两个变量:
- 更新
currentMax
: - 对于当前元素
nums[i]
,currentMax
有两种选择:- 要么只取当前元素
nums[i]
。 - 要么将当前元素
nums[i]
加到之前的currentMax
上。 选择这两种情况中的较大值作为新的currentMax
,即currentMax = max(nums[i], currentMax + nums[i])
。
- 要么只取当前元素
- 更新
globalMax
:将currentMax
和globalMax
进行比较,如果currentMax
大于globalMax
,则更新globalMax
为currentMax
,即globalMax = max(globalMax, currentMax)
。
二解用分治法 类似递归 遍历二叉树的思路
leetcode题解有详细解释,在此代码中附上我的浅显理解
1 | func maxSubArray(nums []int) int { |
56.合并区间
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
1 | 输入:intervals = [[1,3],[2,6],[8,10],[15,18]] |
示例 2:
1 | 输入:intervals = [[1,4],[4,5]] |
提示:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
简单的排序解
算是用上了GO的语法糖sort.Slice
1 | func merge(intervals [][]int) [][]int { |
关键在于直接使用**sort.Slice
定义了对区间的排序方式,依左边界从小到大排序**
再取最后一个合并后的区间,即当前包含了的区间的最右端,与排序后的当前区间进行比较
若目前区间的左端点小于合并后的最右端,证明此区间可以并入最后一个合并后的区间,右端点取二者最大值
否则将当前区间添加到合并后区间数组集中
遍历得出最终结果
189.轮转数组
给定一个整数数组 nums
,将数组中的元素向右轮转 k
个位置,其中 k
是非负数。
示例 1:
1 | 输入: nums = [1,2,3,4,5,6,7], k = 3 |
示例 2:
1 | 输入:nums = [-1,-100,3,99], k = 2 |
提示:
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
0 <= k <= 105
你知道的,我们GO语言的数组是Slice
,是有语法糖的()
一步到位解:
这里第一次写时出现了问题
函数内部对
nums
切片的重新赋值不会影响到函数外部传入的原始切片。在 Go 语言里,虽然切片是引用类型,但当对
nums
进行重新赋值时,实际上只是改变了函数内部的nums
变量指向,而原始切片本身并没有被修改。使用
temp
暂存,再使用copy
函数将temp
中元素复制回原切片nums
1 | func rotate(nums []int, k int) { |
二解 标准答案 反转反转再反转
先整体反转,再反转其
1 | func rotate(nums []int, k int) { |
三解,使用一个与原切片相同长度的新切片,来放置移动位置后的元素
再将新切片复制到原切片
1 | func rotate(nums []int, k int) { |
四解,三解的优化,直接环状替换
Q:为什么必须要使用双层循环?
A:环状替换的核心思路:
n % k
结果为同一值,即Hash结果为同一值的所有元素,构成了一个需要轮换的环 外层循环相当于在遍历所有的这些“环”
内层循环则是在某个“环”内部,对这些元素进行轮换
1 | func rotate(nums []int, k int) { |
详细些的解释:
外层循环
1 | for start := 0; count < n; start++ { |
- 处理多个不相交的环:在某些情况下,数组可能会被分成多个不相交的环。外层循环的作用是从不同的起始位置开始,尝试启动新的环替换操作,确保所有元素都能被正确处理。
start
变量表示当前开始替换的元素索引,count
用于记录已经替换的元素数量,当count
达到数组长度n
时,说明所有元素都已经被替换过,外层循环结束。
内层循环
1 | current := start |
- 完成一个环的替换:内层循环从
start
位置开始,不断将元素移动到其轮转后的位置,直到回到起始位置start
。具体步骤如下:- 计算当前元素要移动到的位置
next
。 - 保存
next
位置原来的元素到temp
。 - 将当前元素
prev
放到next
位置。 - 更新
prev
为temp
的值。 - 更新
current
为next
。 count
加 1 表示已经替换了一个元素。- 如果
current
等于start
,说明已经回到起始位置,当前环的替换完成,跳出内层循环。
- 计算当前元素要移动到的位置
多个不相交环示例:
1 | nums := {1, 2, 3, 4} |
此时存在两个不相交环
1 | 1 -> 3 -> 1 |
若是如同题目示例一nums = [1, 2, 3, 4, 5, 6, 7] k = 3
,则只有一个环存在,即:
1 | 1 -> 4 -> 7 -> 3 -> 6 -> 2 -> 5 -> 1 |