结论
for循环中三个表达式:
for initialization; condition; post { }
初始initialization只会评估一次,后续更新表达式值将不起作用,但post可以实现更新
- map 循环判断某个元素是否存在时常出现下面问题
for _, ok1 := numsSet[num+1]; ok1; {
...
更新num值,但ok1的值不会被更新,死循环
}
---------------------------------------------------------
for _, ok := m[num]; ok; _, ok = m[num] {
更新num值,ok在for循环第三个表达式中被跟新,可以实现功能
}
-----------------------------------------------------------
for _, ok := m[num]; ok; {
...
// 内部手动更新也可以,关键点就是ok这个循环遍历只在第一次遍历的时候创建并评估
_, ok = m[num]
}
问题分析
使用for循环遍历判断某个元素是否存在,会存在一定的问题
对 for _, ok1 := numsSet[num+1]; ok1; {...}
这行代码的问题分析:
错误分析:
- 在 Go 语言中,
for
语句的迭代子句可以有以下几种形式:for initialization; condition; post { }
// 初始initialization只会评估一次,后续更新表达式值将不起作用,但post可以更新for condition { }
for { }
当 you 尝试使用 for _, ok1 := numsSet[num+1]; ok1; {...}
时,存在以下错误:
- 即使 you 正确接收了这两个值,如
_, ok1 := numsSet[num+1]
,for
循环的条件部分ok1
只会在循环开始时被评估一次,而不会在每次迭代后重新评估(因此想着通过函数内部修改num,再评估一次_, ok1 := numsSet[num+1]是不可行的),因此无法实现循环的正确终止条件。
正确写法1:利用for循环第三个表达式,更新第二个判断条件
核心在于:for _, ok := m[num]; ok; _, ok = m[num] {...}
func findContinueNum2(nums []int) int {
m := map[int]struct{}{}
for _, val := range nums {
m[val] = struct{}{}
}
res := 1
for k, _ := range m {
curRes := 1
// 每个key验证
if _, exist := m[k-1]; !exist {
// 第一个数,统计最长
num := k + 1
for _, ok := m[num]; ok; _, ok = m[num] {
curRes++
res = max(res, curRes)
num++
}
}
}
return res
}
正确写法2:
package main
func findContinueNum2(nums []int) int {
numsSet := map[int]struct{}{}
for _, val := range nums {
numsSet[val] = struct{}{}
}
res := 1
for k := range numsSet {
curRes := 1
if _, ok := numsSet[k-1];!ok {
// 第一个数,起点
num := k
for {
_, ok1 := numsSet[num+1]
if!ok1 {
break
}
curRes++
res = max(curRes, res)
num++
}
}
}
return res
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
代码解释:
- 在
findContinueNum2
函数中,首先创建了一个map[int]struct{}
来存储nums
切片中的元素。 - 然后遍历
numsSet
中的键。- 当
k-1
不在numsSet
中时,将k
作为连续序列的起始元素。 - 接着进入一个无限
for
循环,在每次迭代中,使用_, ok1 := numsSet[num+1]
来检查num+1
是否在numsSet
中。- 如果
ok1
为false
,使用break
终止内部的for
循环。 - 否则,更新
curRes
的值并将num
加 1。
- 如果
- 当
max
函数用于比较curRes
和res
的大小,返回较大的值。
使用示例:
func main() {
nums := []int{1, 2, 3, 5, 6, 7, 9, 10, 11}
result := findContinueNum2(nums)
println(result)
}
代码解释:
- 在
main
函数中,定义了一个整数切片nums
。 - 调用
findContinueNum2
函数并将结果存储在result
中。 - 最后打印结果。
上述代码通过修正后的 for
循环结构,能够正确处理连续元素的查找和计数,避免了原代码中 for
循环使用不当的问题。