一.力扣数组刷题每日一题(4/30)(2022/4/18——?)

备注:第三题方法二另解中有不会的地方,有空继续学 

1.485. 最大连续 1 的个数

给定一个二进制数组 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
}

2.495. 提莫攻击

在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。

当提莫攻击艾希,艾希的中毒状态正好持续 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
}

3.414. 第三大的数 

给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。

示例 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
}

代码如上所述,有两处地方我不理解,想不明白就先放下了,之后懂了再写前置知识点和注释

4.628. 三个数的最大乘积 

给你一个整型数组 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
    }
}

5.

集合 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

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值