代码随想录算法训练营第七天| 454. 四数相加 II、383. 赎金信、15. 三数之和、18. 四数之和
前言
今天是看了视频之后,先用C++打了草稿,然后学习涉及的go语法,最后独立写出Go代码,还是这个步骤学语言效率高一点。上来直接尝试用go写,然后现学用到的知识,这样的效率太低,而且有点浆糊。
454. 四数相加 II
题目链接:454. 四数相加 II
思路
最基础的想法是四个数组轮流遍历,但是这样的时间复杂度太高,于是想到分两个部分遍历,这样就把时间复杂度降低到n方。
- 使用map存储nums1+nums2的值,其对应键值为 map[a+b] = a+b大小出现的次数;
- 遍历nums3与nums4,如果有map的key里有-(c+d),那么count就需要加上map的value值;
- 最后返回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个小写英文字母,所以用一个数组就可以实现哈希:
- 新建一个map(字母数组)存放magazine,v为出现次数
- 遍历ransomNote数组
- 判断该字符是否在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. 三数之和
思路
由于是在一个数组中寻找三元组,所以可以通过排序后双指针的滑动进行解题:
- 对数组进行排序
- .排序后如果第一个值大于0,则直接返回res
- 对排序后的数组去重a
- 定义左右指针,讨论三元组存在情况
- 找到一个三元组后,对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:
- 建立res存放符合条件的四元组
- 排序
- 第一层遍历,确定第一个值
- 按三数之和为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
}