代码随想录算法训练营第七天| 454. 四数相加 II、383. 赎金信、15. 三数之和、18. 四数之和

代码随想录算法训练营第七天| 454. 四数相加 II、383. 赎金信、15. 三数之和、18. 四数之和

前言

今天是看了视频之后,先用C++打了草稿,然后学习涉及的go语法,最后独立写出Go代码,还是这个步骤学语言效率高一点。上来直接尝试用go写,然后现学用到的知识,这样的效率太低,而且有点浆糊。

454. 四数相加 II

题目链接:454. 四数相加 II

思路

最基础的想法是四个数组轮流遍历,但是这样的时间复杂度太高,于是想到分两个部分遍历,这样就把时间复杂度降低到n方

  1. 使用map存储nums1+nums2的值,其对应键值为 map[a+b] = a+b大小出现的次数
  2. 遍历nums3与nums4,如果有map的key里有-(c+d),那么count就需要加上map的value值;
  3. 最后返回count即可。

解题代码

func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
    var newMap map[int]int 
    newMap = make(map[int]int)
    count := 0

    for _,a := range nums1{  //遍历nums1与nums2,用map记录a+b的值
        for _,b := range nums2{
            newMap[a+b]++
        }
    }

    for _,c := range nums3{
        for _,d := range nums4{
            if v,ok := newMap[-c-d]; ok{   //在nums3与nums4中查找是否有-(a+b)的值
                count += v
            }
            //或者可以直接写
            //count += newMap[-c-d]
        }
    }
    return count
}

383. 赎金信

题目链接:383. 赎金信

思路

我太开心了,这题是自己用go独立做出来的!
贴一下思路吧,这道题跟昨天的有效字母异位几乎是一个想法,由于只有26个小写英文字母,所以用一个数组就可以实现哈希:

  1. 新建一个map(字母数组)存放magazine,v为出现次数
  2. 遍历ransomNote数组
  3. 判断该字符是否在map里,在就v–,不在就return

解题代码

func canConstruct(ransomNote string, magazine string) bool {

    //1.新建一个map(字母数组)存放magazine,v为出现次数
    //2.遍历ransomNote数组
    //3.判断该字符是否在map里,在就v--,不在就return
    arr := [26]int{}
    for _,v := range magazine{
        arr[v-rune('a')]++
    }
    for _,val := range ransomNote{
        if arr[val-rune('a')] > 0{
            arr[val-rune('a')]--
        }else{
            return false
        }
    }  
    return true
}

15. 三数之和

题目链接:15. 三数之和

思路

由于是在一个数组中寻找三元组,所以可以通过排序双指针的滑动进行解题:

  1. 对数组进行排序
  2. .排序后如果第一个值大于0,则直接返回res
  3. 对排序后的数组去重a
  4. 定义左右指针,讨论三元组存在情况
  5. 找到一个三元组后,对b c去重

解题代码

func threeSum(nums []int) [][]int {
    //1.对数组进行排序
    //2.排序后如果第一个值大于0,则直接返回nil
    //3.对排序后的数组去重a
    //4.定义左右指针,讨论三元组存在情况
    //5.找到一个三元组后,对b c去重
    sort.Ints(nums)
    res := [][]int{}

    for i:=0;i<len(nums)-2;i++{
        a := nums[i]
        if a>0{
            return res
        }
        if i>0 && nums[i-1]==a{       //去重操作
            continue
        }

        left := i+1
        right := len(nums)-1
        for left<right{
            b,c := nums[left],nums[right] 
            if a+b+c == 0{
                res = append(res,[]int{a,b,c})
                for left<right && nums[left]==b{  //不是直接指针后移,需要判断一下是否要连续后移
                    left++
                }
                for left<right && nums[right]==c{  //同理
                    right--
                }
            }else if a+b+c>0{
                right--
            }else if a+b+c<0{
                left++
            }  
        }  
    }
    return res
}

18. 四数之和

题目链接:18. 四数之和

思路

这道题与上题没有太大差别,就是将三数之和为0,转换为三数之和为target-a,唯一的不同就是不可以通过第一个数的大小判断是否可以直接return:

  1. 建立res存放符合条件的四元组
  2. 排序
  3. 第一层遍历,确定第一个值
  4. 按三数之和为target-a,利用双指针完成

解题代码

func fourSum(nums []int, target int) [][]int {

    //1.建立res存放符合条件的四元组
    //2.排序
    //3.第一层遍历,确定第一个值
    //4.按三数之和为target-a,利用双指针完成
    
    res := [][]int{}
    sort.Ints(nums)

    if len(nums)<4{
        return nil
    }

    for i:=0;i<len(nums)-3;i++{
        a:=nums[i]  
        if i>0 && nums[i-1]==a{   //对a去重
            continue
        }

        //开始三数求和
        for j:=i+1;j<len(nums)-2;j++{
            //确定第二个数
            b := nums[j]
            if j>i+1&&nums[j-1]==b{    //对b去重
                continue
            }
            //建立双指针
            left := j+1
            right := len(nums)-1
            for left<right{
                c,d := nums[left],nums[right]

                if a+b+c+d==target{
                    res = append(res,[]int{a,b,c,d})   //符合情况,加入
                    for left<right&&c==nums[left]{
                        left++
                    }
                    for left<right&&d==nums[right]{
                        right--
                    }
                }else if a+b+c+d<target{
                    left++
                }else if a+b+c+d>target{
                    right--
                }
            }
        }
    }
    return res
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值