代码随想录第六天|454四数相加II383赎金信15三数之和18四数之和|01笔记

181 阅读2分钟
  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 暴力方法来遍历四个数组的话,时间复杂度会达到O(n^4)。也许可以使用哈希法存储两层或三层的方法来记录值。
  • 讲解观后感

  • 本题是分开的四个数组。可以分为个每两个一组,用O(n^2)存储前两组的和以及出现的次数。构建出返回值count,再遍历后两组的和,能够使a+b+c+d=0满足时遍增加count。
  • 解题代码

  •     func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
            AB := make(map[int]int)
            for _,m:=range nums1 {
                for _,n:=range nums2 {
                    AB[m+n] += 1
                }
            }
            count := 0
            
            for _,o:=range nums3 {
                for _,p:=range nums4 {
                    if _,ok:=AB[0-o-p];ok {
                        count += AB[0-o-p]
                    }
                }
            } 
            return count
        
        }
    
  • 383赎金信

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 这道题方法类似与《242字母异位词》,只需要存储magzine的字母及出现次数,再减去信件中的字母,不为-1即视为true。
  • 解题代码

  •     func canConstruct(ransomNote string, magazine string) bool {
            set := [26]int{}
        
            for _,i:= range magazine {
                set[i-'a']++
            }
            for _,s:= range ransomNote {
                set[s-'a']--
                if set[s-'a'] <0 {
                    return false
                }
            }
        
            return true
        }
    
  • 15三数之和

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 暴力的方法貌似是可以用三次遍历找出符合条件的组合,然后再进行去重,然而在思考去重逻辑的过程中发现很难实现。
  • 讲解观后感

  • 这道题目使用哈希法并不十分合适,因为在去重的操作中有很多细节需要注意,在面试中很难直接写出没有bug的代码。而且使用哈希法 在使用两层for循环的时候,能做的剪枝操作很有限,虽然时间复杂度是O(n^2),也是可以在leetcode上通过,但是程序的执行时间依然比较长 。双指针法的方式更合适
  • 遇到问题

  • 忘记第一个数字去重代码,结果出现重复
  • 补充以下代码段后解决
  •     if i > 0 && n1 == nums[i-1] {
        			continue
        		}
    
  • 第二三个字母去重时,指针越界:
  •     l, r := i+1,len(nums)-1
                for l < r {
                    n2, n3 := nums[l], nums[r]
                    if n1 + n2 + n3 == 0 { 
                        for l < r && nums[l] == nums[l+1] {
                            l++
                        }
                        for l < r && nums[r] == nums[r-1] {
                            r--
                        }
                        ans = append(ans,[]int{n1,n2,n3})
                    } else if n1 + n2 + n3 < 0 {
                        l++
                    } else {
                        r--
                    }
                }
    
  • 解决方法:将 nums[l+1] nums[r-1]替换为n2n3
  • 解题代码

  •     func threeSum(nums []int) [][]int {
            ans := [][]int{}
            sort.Ints(nums)
        
            for i:=0;i<len(nums)-2;i++ {
                n1 := nums[i]
                if n1>0  {
                    break
                }
                if i > 0 && n1 == nums[i-1] {
        			continue
        		}
                l, r := i+1,len(nums)-1
                for l < r {
                    n2, n3 := nums[l], nums[r]
                    if n1 + n2 + n3 == 0 { 
                        for l < r && nums[l] == n2 {
                            l++
                        }
                        for l < r && nums[r] == n3 {
                            r--
                        }
                        ans = append(ans,[]int{n1,n2,n3})
                    } else if n1 + n2 + n3 < 0 {
                        l++
                    } else {
                        r--
                    }
                }
            }
            return ans
        }
    
  • 18四数之和

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 方法类似于《三数之和》的方法,只不过是多套一层循环,三数之和的复杂度是O(n^2),四数之和的复杂度为O(n^3)
  • 第二层的剪枝操作可以优化为
  •     if (nums[k] + nums[i] > target && nums[i] >= 0) {
            break;
        }
    
  • 解题代码

  •     func fourSum(nums []int, target int) [][]int {
        	if len(nums) < 4 {
        		return nil
        	}
        	sort.Ints(nums)
        	var res [][]int
        	for i := 0; i < len(nums)-3; i++ {
        		n1 := nums[i]
        		// if n1 > target { // 不能这样写,因为可能是负数
        		// 	break
        		// }
                if n1 > target && (n1>=0 || target>=0) {
                    break
                }
        		if i > 0 && n1 == nums[i-1] {  // 对nums[i]去重
        			continue
        		}
        		for j := i + 1; j < len(nums)-2; j++ {
        			n2 := nums[j]
        			if j > i+1 && n2 == nums[j-1] {  // 对nums[j]去重
        				continue
        			}
                    if (nums[i] + nums[j] > target && nums[j] >= 0) {
                        break
                    }
        			l := j + 1
        			r := len(nums) - 1
        			for l < r {
        				n3 := nums[l]
        				n4 := nums[r]
        				sum := n1 + n2 + n3 + n4
        				if sum < target {
        					l++
        				} else if sum > target {
        					r--
        				} else {
        					res = append(res, []int{n1, n2, n3, n4})
        					for l < r && n3 == nums[l+1] { // 去重
        						l++
        					}
        					for l < r && n4 == nums[r-1] { // 去重
        						r--
        					}
        					// 找到答案时,双指针同时靠近
        					r--
        					l++
        				}
        			}
        		}
        	}
        	return res
        }