备注:第三题方法二另解中有不会的地方,有空继续学
给定一个二进制数组 nums , 计算其中最大连续 1 的个数。
示例 1:
输入:nums = [1,1,0,1,1,1]
输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.
示例 2:
输入:nums = [1,0,1,1,0,1]
输出:2
提示:
1 <= nums.length <= 105
nums[i] 不是 0 就是 1.
前置知识点:
1.不同的赋值方式:var num int =1,var age =20,age :=30
name, age :="Tom", 18
var name string
name :="Tom"
2.for循环语句:for 初始语句;条件表达式;赋值表达式 { 循环体 }
3.if语句:if 表达式1 {
分支1
} else if 表达式2 {
分支2
} else {
分支3
}
4.var 数组变量名 [数组长度]元素类型
var student [3]string
5.range是Go语言中非常常用的一个关键字,其主要作用就是配合for关键字对数组以及之后会介
绍到的切片和映射等数据结构进行迭代。
for k, v := range num {
fmt.Println("变量k:", k," ","变量v:", v)
}
range后接的表达式称为range表达式,本例的range表达式为数组。在迭代时,关键字range会返
回两个值,分别由变量k和v接收。其中k是当前循环迭代到的索引位置,v是该位置对应元素值的一
份副本。
6.匿名变量
在赋值给多个变量时,如果存在不需要接收值的变量,可以使用匿名变量来代替。
a,_ := ReturnData()
7.函数
func 函数名(参数列表) (返回参数列表){
函数体
}
例如:
1 func add(x int,y int) (sum int) {
02 sum =x+y
03 return sum
04 }
func add(x ,y int) (sum int) {
02 sum =x+y
03 return sum
04 }
力扣官方题解:
方法一:一次遍历
为了得到数组中最大连续 1 的个数,需要遍历数组,并记录最大的连续 1 的个数和当前的连续 1 的个数。如果当前元素是 1,则将当前的连续 1的个数加 1,否则,使用之前的连续 1 的个数更新最大的连续 1的个数,并将当前的连续 1 的个数清零。
遍历数组结束之后,需要再次使用当前的连续 1 的个数更新最大的连续 1 的个数,因为数组的最后一个元素可能是 1,且最长连续 1的子数组可能出现在数组的末尾,如果遍历数组结束之后不更新最大的连续 1的个数,则会导致结果错误。
代码如下:
func findMaxConsecutiveOnes(nums []int) int {
cnt, maxcnt := 0, 0
for _, v := range nums{/*第一个存放下标,不需要它,于是用匿名变量存放它,
第二个存放下标对应的值,从第0个位置开始一直遍历到最后*/
if v == 1{//遇到1计数器加一
cnt++
}else{//遇到非1,将统计到的连续1的最大值与当前的最大值进行比较
maxcnt = max(maxcnt, cnt)
cnt = 0//连续1的数目归零,再次重新计数
}
}
maxcnt = max(maxcnt, cnt)/*因为当最后一个元素为1时,前面的if分支会进行++操作,
没有与maxcnt进行最后一次的比较,所以再比一次*/
return maxcnt
}
func max(a, b int)int{//返回两个数的最大值
if a > b{
return a
}
return b
}
在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。
当提莫攻击艾希,艾希的中毒状态正好持续 duration 秒。
正式地讲,提莫在 t 发起发起攻击意味着艾希在时间区间 [t, t + duration - 1](含 t 和 t + duration - 1)处于中毒状态。如果提莫在中毒影响结束 前 再次攻击,中毒状态计时器将会 重置 ,在新的攻击之后,中毒影响将会在 duration 秒后结束。
给你一个 非递减 的整数数组 timeSeries ,其中 timeSeries[i] 表示提莫在 timeSeries[i] 秒时对艾希发起攻击,以及一个表示中毒持续时间的整数 duration 。
返回艾希处于中毒状态的 总 秒数。
示例 1:
输入:timeSeries = [1,4], duration = 2
输出:4
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 4 秒,提莫再次攻击艾希,艾希中毒状态又持续 2 秒,即第 4 秒和第 5 秒。
艾希在第 1、2、4、5 秒处于中毒状态,所以总中毒秒数是 4 。
示例 2:
输入:timeSeries = [1,2], duration = 2
输出:3
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 2 秒,提莫再次攻击艾希,并重置中毒计时器,艾希中毒状态需要持续 2 秒,即第 2 秒和第 3 秒。
艾希在第 1、2、3 秒处于中毒状态,所以总中毒秒数是 3 。
提示:
1 <= timeSeries.length <= 104
0 <= timeSeries[i], duration <= 107
timeSeries 按 非递减 顺序排列
前置知识点:
1.遍历数组:
var student = [...]string{"Tom","Ben","Peter"}
07 for k,v := range student{
08 fmt.Println("数组下标:",k,",对应元素",v)
09 }
执行结果如下:
数组下标: 0 ,对应元素 Tom
数组下标: 1 ,对应元素 Ben
数组下标: 2 ,对应元素 Peter
range后接的表达式称为range表达式,本例的range表达式为数组。在迭代时,关键字range会返
回两个值,分别由变量k和v接收。其中k是当前循环迭代到的索引位置,v是该位置对应元素值的一
份副本。
力扣官方解答思想如下:
方法一:单次扫描
我们只需要对数组进行一次扫描就可以计算出总的中毒持续时间。我们记录艾希恢复为未中毒的起始时间 expired,设艾希遭遇第 i次的攻击的时间为timeSeries[i]。当艾希遭遇第 i 攻击时:如果当前他正处于未中毒状态,则此时他的中毒持续时间应增加 duration,同时更新本次中毒结束时间 expired 等于timeSeries[i] +duration;
如果当前他正处于中毒状态,由于中毒状态不可叠加,我们知道上次中毒后结束时间为 expired,本次中毒后结束时间为 timeSeries[i]+duration,因此本次中毒增加的持续中毒时间为 timeSeries[i]+duration−expired;
代码如下:
func findPoisonedDuration(timeSeries []int, duration int) int{
ans, expired := 0, 0//ans:持续时间,expired:中毒结束即恢复正常的时间
for _, t := range timeSeries{//遍历数组timeSeries,匿名变量存放下标,t存放中毒时间
if t >= expired{//中毒在恢复健康时及以后,直接加上中毒的持续时间
ans += duration
}else{//中毒时再次中毒,从现在中毒的时间开始再持续duration时间,但有重复计算的时间,
//即为现在中毒的时间到上次中毒结束的时间(expired)
ans += t + duration - expired
}
expired = t + duration//每次更新本次中毒后恢复正常的时间点
}
return ans
}
给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。
示例 1:
输入:[3, 2, 1]
输出:1
解释:第三大的数是 1 。
示例 2:
输入:[1, 2]
输出:2
解释:第三大的数不存在, 所以返回最大的数 2 。
示例 3:
输入:[2, 2, 3, 1]
输出:1
解释:注意,要求返回第三大的数,是指在所有不同数字中排第三大的数。
此例中存在两个值为 2 的数,它们都排第二。在所有不同数字中排第三大的数为 1 。
提示:
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
方法一:排序
前置知识点:
一.方法一:排序
1.sort排序:
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
Golang在标准包中,官方有提供sort包中Sort()函数提供排序功能。并且天然支持[]int,[]float64,[]string切片的排序查找功能,并且也能够实现对自定义类型集合的排序。
顺序、升序:由小到大; 逆序、降序:从大到小
Sort()方法定义如下:
func Sort(data Interface)
func Reverse(data Interface) Interface
1.1 sort 操作的对象通常是一个 slice
golang 对常见的 []int 和 []string 分别定义了 IntSlice 和 StringSlice, 实现了各自的排序接口。而 sort.Ints 和 sort.Strings 可以直接对 []int 和 []string 进行排序
sort包定义了一个IntSlice类型,并且实现了sort.Interface接口:
假设我们需要对 []int 切片中的元素进行排序,其实现代码如下:
sort.Sort(IntSlice(nums))
例子:
ss := []string{"surface", "ipad", "mac pro", "mac air", "think pad", "idea pad"}
sort.Strings(ss)
sort.Sort(sort.Reverse(sort.StringSlice(ss)))
1.2 使用 sort.Reverse 进行逆序排序:
a := []int{4,3,2,1,5,9,8,7,6}
sort.Sort(sort.Reverse(sort.IntSlice(a)))
力扣官方题解:
将数组从大到小排序后,从头开始遍历数组,通过判断相邻元素是否不同,来统计不同元素的个数。如果能找到三个不同的元素,就返回第三大的元素,否则返回最大的元素。
func thirdMax(nums []int) int {
sort.Sort(sort.Reverse(sort.IntSlice(nums)))//对数组即int型的切片进行逆向排序,Sort(Reverse(IntSlice(nums)))
for i, diff := 1, 1; i < len(nums); i++{//从第二个元素开始考虑,因为第一个元素前面不会有能和它重复的元素
if nums[i] != nums[i - 1]{//当前元素和前面的元素不同
diff++//即为第diff++大的数
if diff == 3{
return nums[i]
}
}
}
return nums[0]
}
方法二:一次遍历
前置知识点:
1.c := math.MinInt64,math.MinInt64即为最小的64位int数
力扣官方题解:
我们可以遍历数组,并用三个变量 a、b 和 c 来维护数组中的最大值、次大值和第三大值,以模拟方法二中的插入和删除操作。为方便编程实现,我们将其均初始化为小于数组最小值的元素,视作「无穷小」,比如 -2^{63} 等。
遍历数组,对于数组中的元素 num:
- 若num>a,我们将 c 替换为 b,b 替换为 a,a 替换为 num,这模拟了将 num 插入有序集合,并删除有序集合中的最小值的过程;
- 若 a>num>b,类似地,我们将 c 替换为 b,b 替换为 num,a保持不变;
- 若 b>num>c,类似地,我们将 c 替换为num,a 和 b 保持不变;
- 其余情况不做处理。
遍历结束后,若 c 仍然为 -2^{63},则说明数组中不存在三个或三个以上的不同元素,即第三大的数不存在,返回 a,否则返回 c。
代码如下:
func thirdMax(nums []int) int{
a, b, c := math.MinInt64, math.MinInt64, math.MinInt64//给a,b,c赋值最小的int数
for _, num := range nums{
if num > a{//比较nums数组里的数与a,b,c的大小,将num放置到合适的位置
a, b, c = num, a, b
}else if num < a && num > b{//当num的值与abc的值相等时为重复值,忽略不处理
b, c = num, b
}else if num < b && num > c{
c = num
}
}
if c == math.MinInt64{//数组里不重复的数小于3个,导致c的初始值未发生变化
return a
}
return c
}
另一种不依赖元素范围的做法是,将 aa、bb 和 cc 初始化为空指针或空对象,视作「无穷小」,并在比较大小前先判断是否为空指针或空对象。遍历结束后,若 cc 为空,则说明第三大的数不存在,返回 aa,否则返回 cc。
前置知识点:
1.var a, b, c *int 定义了三个int型的指针,且未进行初始化,则a, b, c均为空指针,即 a == nil(bc同理),nil代表空值
在go语言中,nil可以代表下面这些类型的零值:
指针类型(包括unsafe中的)
map类型
slice类型
function类型
channel类型
interface类型
nil是指申明了变量,但没有赋值:在Go语言中,如果你声明了一个变量但是没有对它进行赋值操作,那么这个变量就会有一个类型的默认零值。
2.for _, num := range nums {
if a == nil || num > *a {
a, b, c = &num, a, b
} else if num < *a && (b == nil || num > *b) {
b, c = &num, b
} else if *b > num && (c == nil || num > *c) {
c = &num
}
}
fmt.Println(*c)
此时程序会报错,显示:invalid memory address or nil pointer dereference不存在的地址
代码如下:
func thirdMax(nums []int) int {
var a, b, c *int
for _, num := range nums {
num := num
if a == nil || num > *a {
a, b, c = &num, a, b
} else if *a > num && (b == nil || num > *b) {
b, c = &num, b
} else if b != nil && *b > num && (c == nil || num > *c) {
c = &num
}
}
if c == nil {
return *a
}
return *c
}
代码如上所述,有两处地方我不理解,想不明白就先放下了,之后懂了再写前置知识点和注释
给你一个整型数组 nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。
示例 1:
输入:nums = [1,2,3]
输出:6
示例 2:
输入:nums = [1,2,3,4]
输出:24
示例 3:
输入:nums = [-1,-2,-3]
输出:-6
提示:
3 <= nums.length <= 104
-1000 <= nums[i] <= 1000
前置知识点:
1. IntSlice类型及[]int排序
sort包定义了一个IntSlice类型,并且实现了sort.Interface接口:并且提供的sort.Ints()方法使用了该IntSlice类型:
func Ints(a []int) { Sort(IntSlice(a)) }
对[]int切片排序是更常使用sort.Ints(),而不是直接使用IntSlice类型:
s := []int{5, 2, 6, 3, 1, 4} // 未排序的切片数据
sort.Ints(s)
fmt.Println(s) //将会输出[1 2 3 4 5 6]
如果要使用降序排序,显然要用Reverse()方法:
s := []int{5, 2, 6, 3, 1, 4} // 未排序的切片数据
sort.Sort(sort.Reverse(sort.IntSlice(s)))
fmt.Println(s) //将会输出[6 5 4 3 2 1]
官方题解:方法一排序:
首先将数组排序。
如果数组中全是非负数,则排序后最大的三个数相乘即为最大乘积;如果全是非正数,则最大的三个数相乘同样也为最大乘积。
如果数组中有正数有负数,则最大乘积既可能是三个最大正数的乘积,也可能是两个最小负数(即绝对值最大)与最大正数的乘积。
综上,我们在给数组排序后,分别求出三个最大正数的乘积,以及两个最小负数与最大正数的乘积,二者之间的最大值即为所求答案。
代码如下:
func maximumProduct(nums []int) int {
sort.Ints(nums)
n := len(nums)
//三个最大正数的乘积,以及两个最小负数与最大正数的乘积,二者之间的最大值即为所求答案。
return max(nums[n - 1] * nums[n - 2] * nums[n - 3], nums[0] * nums[1] * nums[n - 1])
}
func max(a, b int) int {
if a > b{
return a
}else{
return b
}
}
方法二:线性扫描
在方法一中,我们实际上只要求出数组中最大的三个数以及最小的两个数,因此我们可以不用排序,用线性扫描直接得出这五个数。
前置知识点:
1.遍历数组
数组元素可以通过数组下标来读取或修改,数组下标从0开始,第一个元素的数组下标为0,
第二个元素的数组下标为1,以此类推。
我们现在可以通过遍历数组的方式(for循环)来对其进行打印。
var student = [...]string{"Tom","Ben","Peter"}
07 for k,v := range student{
08 fmt.Println("数组下标:",k,",对应元素",v)
执行结果如下:
数组下标: 0 ,对应元素 Tom
数组下标: 1 ,对应元素 Ben
数组下标: 2 ,对应元素 Peter
代码如下:
func maximumProduct(nums []int) int {
min1, min2 := math.MaxInt64, math.MaxInt64//两个最小值里存放最大的整型数,这样遇到任何一个整型数都可以存放进去
max1, max2, max3 := math.MinInt64, math.MinInt64, math.MinInt64//三个最大值
for _, num := range nums{
if num < min1{
min2 = min1
min1 = num
}else if num < min2{
min2 = num
}
if num > max1{
max3 = max2
max2 = max1
max1 = num
}else if num > max2{
max3 = max2
max2 = num
}else if num > max3{
max3 = num
}
}
return max(max1 * max2 * max3, max1 * min1 * min2)
}
func max(a, b int) int {
if a > b{
return a
}else{
return b
}
}
集合 s
包含从 1
到 n
的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。
给定一个数组 nums
代表了集合 S
发生错误后的结果。
请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
示例 1:
输入:nums = [1,2,2,4] 输出:[2,3]
示例 2:
输入:nums = [1,1] 输出:[1,2]
提示:
2 <= nums.length <= 104
1 <= nums[i] <= 104