leetcode打卡笔记(不断更新......)

一、链表

1、移除链表元素

func removeElements(head *ListNode, val int) *ListNode {
    p := &ListNode{}
    p.Next = head
	
	pre := p
    cur := head

	for cur != nil {
		if cur.Val == val {
			pre.Next = cur.Next
			cur = cur.Next
		}else {
			pre = cur
			cur = cur.Next
		}
	}
	return p.Next
}

2、设计链表 707

type MyLinkedList struct {
	head *ListNode
	size int
}

func Constructor() MyLinkedList {
	return MyLinkedList{&ListNode{}, 0}
}

func (this *MyLinkedList) Get(index int) int {
	if index < 0 || index >= this.size {
		return -1
	}
	cur := this.head
	for i := 0; i <= index; i++ {
		cur = cur.Next
	}
	return cur.Val
}

func (this *MyLinkedList) AddAtHead(val int) {
	this.AddAtIndex(0, val)
}

func (this *MyLinkedList) AddAtTail(val int) {
	this.AddAtIndex(this.size, val)
}

func (this *MyLinkedList) AddAtIndex(index int, val int) {
	if index > this.size {
		return
	}
	this.size++

	pre := this.head
	for i := 0; i < index; i++ {
		pre = pre.Next
	}

	cur := &ListNode{Val: val, Next: nil}
	cur.Next = pre.Next
	pre.Next = cur
}

func (this *MyLinkedList) DeleteAtIndex(index int) {
	if index < 0 || index >= this.size {
		return
	}
	this.size--
	p := this.head
	for i := 0; i < index; i++ {
		p = p.Next
	}
	p.Next = p.Next.Next
}


/**
 * Your MyLinkedList object will be instantiated and called as such:
 * obj := Constructor();
 * param_1 := obj.Get(index);
 * obj.AddAtHead(val);
 * obj.AddAtTail(val);
 * obj.AddAtIndex(index,val);
 * obj.DeleteAtIndex(index);
 */

3、反转链表

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
//1 2 3 4 5
func reverseList(head *ListNode) *ListNode {
	var pre *ListNode = nil //*
	cur := head
	for cur != nil {
		next := cur.Next //先指向 (位置很关键)
		cur.Next = pre // 反转指针
		pre = cur
		cur = next
	}
	return pre
}

4、两两交换链表中的节点 24

//递归
func swapPairs(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	newHead := head.Next
	head.Next = swapPairs(newHead.Next)
	newHead.Next = head
	return newHead
}
//非递归
func swapPairs(head *ListNode) *ListNode {
	newHead := &ListNode{}
	newHead.Next = head
	temp := newHead
	for temp.Next != nil && temp.Next.Next != nil {
		node1 := temp.Next
		node2 := temp.Next.Next

		temp.Next = node2
		node1.Next = node2.Next
		node2.Next = node1

		temp = node1
	}
	return newHead.Next
}

5、删除链表的倒数第n个节点——19

func removeNthFromEnd(head *ListNode, n int) *ListNode {
	if head == nil {
		return head
	}
	size := 0
	p := head
	for p != nil {
		p = p.Next
		size++
	}
	newHead := &ListNode{0,head}
	cur := newHead
	for i := 0; i < size-n; i++ {
		cur = cur.Next
	}
	if cur.Next.Next != nil {
		cur.Next = cur.Next.Next
	} else {
		cur.Next = nil
	}
	return newHead.Next
}

6、链表相交

思路:双指针
/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func getIntersectionNode(headA, headB *ListNode) *ListNode {
	if headA == nil || headB == nil {
		return nil
	}
	curA := headA
	curB := headB
	for curA != curB {
		if curA == nil {
			curA = headB
		}else{
            curA = curA.Next
        }
		if curB == nil {
			curB = headA
		}else{
            curB = curB.Next
        }

	}
	return curA
}

7、环形链表2——142
题目:找到环的入口位置

//方法一 快慢指针
func detectCycle(head *ListNode) *ListNode {
	slow, fast := head, head
    for fast != nil {
        slow = slow.Next
        if fast.Next == nil {
            return nil
        }
        fast = fast.Next.Next
        if fast == slow {
            p := head
            for p != slow {
                p = p.Next
                slow = slow.Next
            }
            return p
        }
    }
    return nil
}

1、Go 语言中,map 的键是唯一的,如果尝试将相同的键再次插入 map,旧的值会被新的值覆盖。
2、值的类型是 struct{},实际上并不关心值的内容,只关心键的存在性。
3、struct{} 表示一个不包含任何字段的空结构体。这个结构体是零字节大小的,也就是说它不占用任何内存空间。
4、因为它没有字段,所以它的实例在内存中仅占用一个零字节的空间。
5、res[head] 表示从 res 中获取键为 head 的值。通过 _, ok := res[head],我们只关心 ok 这个变量,它表示是否存在键 head。

//方法二 遍历链表,定义map存起来,利用map的键唯一的特性查重
func detectCycle(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return nil
	}
	res := make(map[*ListNode]struct{})
	for head != nil {
		if _, ok := res[head]; ok {
			return head
		}
		res[head] = struct{}{}
		head = head.Next
	}
	return nil
}

哈希表

1、有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

//方法一  切片 没有固定长度,固定长度是数组,可以==直接比较
unc isAnagram(s string, t string) bool {
	if len(s) != len(t) {
		return false
	}
	//切片 没有固定长度,固定长度是数组,可以==直接比较
	var arr_s []int
	var arr_t []int
	for i := 0; i < len(s); i++ {
		arr_s = append(arr_s, int(s[i])-int('a'))
		arr_t = append(arr_t, int(t[i])-int('a'))
	}
	sort.Ints(arr_t)
	sort.Ints(arr_s)
	for i := 0; i < len(arr_s); i++ {
		if arr_t[i] != arr_s[i] {
			return false
		}
	}
	return true
}
// sort.Slice 函数提供了一种对切片进行排序的通用方法。它允许你提供一个自定义的比较函数,用于定义切片元素的排序规则。
// 返回 true 表示 i 位置的元素应该排在 j 位置的元素之前。
func test(s, t string) bool {
	s1, s2 := []byte(s), []byte(t)
	sort.Slice(s1, func(i, j int) bool { return s1[i] < s1[j] })
	fmt.Println(s1)
	sort.Slice(s2, func(i, j int) bool { return s2[i] < s2[j] })
	fmt.Println(s2)
	return string(s1) == string(s2)
}
//方法三 哈希法:维护一个26长的数组,记录出现的字母的数量
func isAnagram(s, t string) bool {
	var c1, c2 [26]int
	for _, ch := range s {
		c1[ch-'a']++
	}
	for _, ch := range s {
		c2[ch-'a']++
	}
	return c1 == c2
}

2、两个数组的交集——349

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序

// 方法一:暴力解法:利用set的键值为一保证唯一性
func intersection(nums1 []int, nums2 []int) []int {
	res := make(map[int]struct{})
	//var res []int
	for i := 0; i < len(nums1); i++ {
		for j := 0; j < len(nums2); j++ {
			if nums1[i] == nums2[j] {
				res[nums1[i]] = struct{}{}
			}
		}
	}
	var resArr []int
	for key, _ := range res {
		resArr = append(resArr, key)
	}
	return resArr
}
//方法二 两个集合(和方法一类似)
func intersection(nums1 []int, nums2 []int) []int {
	set1 := map[int]struct{}{}
	set2 := map[int]struct{}{}
	for _, v := range nums1 {
		set1[v] = struct{}{}
	}
	for _, v := range nums2 {
		set2[v] = struct{}{}
	}
	var res []int
	//为了防止下面代码循环一次
	if len(set1) < len(set2) {
		set1, set2 = set2, set1
	}
	for v := range set2 {
		if _, has := set1[v]; has {
			res = append(res, v)
		}
	}
	return res
}
// 方法三:双指针
func intersection(nums1 []int, nums2 []int) []int {
	sort.Ints(nums1)
	sort.Ints(nums2)
	var res []int
	for i, j := 0, 0; i < len(nums1) && j < len(nums2); {
		x, y := nums1[i], nums2[j]
		if x == y {
			if res == nil || x > res[len(res)-1] {
				res = append(res, x)
			}
			i++
			j++
		} else if x < y {
			i++
		} else {
			j++
		}
	}
	return res
}

3、快乐数——202

//方法一:暴力+ set(利用map构造出set)
func getNum(num int) []int {
	var res []int
	for num != 0 {
		res = append(res, num%10)
		num /= 10
	}
	fmt.Println(res)
	return res
}
func isHappy(n int) bool {
	newNum := 0
	set1 := make(map[int]struct{})
	res := getNum(n)
	for newNum != n {
		newNum := 0
		for _, v := range res {
			newNum += v * v
		}

		if _, has := set1[newNum]; has {
			return false
		} else {
			set1[newNum] = struct{}{}
		}

		if newNum == 1 {
			return true
		}
		res = getNum(newNum)
	}
	return false
}
//方法二:快慢指针法(官网)
//慢速在链表中前进 1 个节点,快跑者前进 2 个节点(对 getNext(n) 函数的嵌套调用)
//如果 n 是一个快乐数,即没有循环,那么快跑者最终会比慢跑者先到达数字 1。
//如果 n 不是一个快乐的数字,那么最终快跑者和慢跑者将在同一个数字上相遇。
func isHappy(n int) bool {
    slow, fast := n, step(n)
    for fast != 1 && slow != fast {
        slow = step(slow)
        fast = step(step(fast))
    }
    return fast == 1
}

func step(n int) int {
    sum := 0
    for n > 0 {
        sum += (n%10) * (n%10)
        n = n/10
    }
    return sum
}

4、两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

// 方法一:暴力法
func twoSum(nums []int, target int) []int {
	for i := 0; i < len(nums)-1; i++ {
		for j := i + 1; j < len(nums); j++ {
			if nums[i]+nums[j] == target {
				var res []int
				res = append(append(res, i), j)
				return res
			}
		}
	}
	return nil
}
// 方法二:哈希
//我们创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。
func twoSum(nums []int, target int) []int {
	hashTable := map[int]int{}
	for i, x := range nums {
		if p, ok := hashTable[target-x]; ok {
			return []int{p, i}
		}
		hashTable[x] = i
	}
	return nil
}

5、两数相加——454

给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

示例 1:
输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释: 两个元组如下:

  1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
  2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
//分组 + 哈希表
func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
	countAB := map[int]int{}
	 // 遍历nums1和nums2数组,统计两个数组元素之和,和出现的次数,放到map中
	for _, v := range nums1 {
		for _, w := range nums2 {
			countAB[v+w]++
		}
	}
	res := 0
	// 遍历nums3和nums4数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来
	for _, v := range nums3 {
		for _, w := range nums4 {
			res += countAB[-v-w]
		}
	}
	return res
}

6、三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释: nums[0] +nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

//排序+双指针
func threeSum(nums []int) [][]int {
	n := len(nums)
	sort.Ints(nums)
	ans := make([][]int, 0)
	for first:=0;first<n;first++{
		if first>0 && nums[first] == nums[first-1]{
			continue
		}
		third := n-1
		target := -1 * nums[first]
		
		for second := first+1;second<n; second++ {
			if second > first + 1 && nums[second] == nums[second-1] {
				continue
			}
			for second < third && nums[second] + nums[third] > target{
				third--
			}
			if second == third {
				break
			}
			if nums[second] + nums[third] == target{
				ans = append(ans,[]int{nums[first],nums[second],nums[third]})
			}
		}
	}
	return ans
}

7、四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • a、b、c 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target
    你可以按 任意顺序 返回答案 。

示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

//排序+双指针
func fourSum1(nums []int, target int) [][]int {
	sort.Ints(nums)
	n := len(nums)
	res := [][]int{}
	for first := 0; first < n; first++ {
		if first > 0 && nums[first] == nums[first-1] {
			continue
		}
		for second := first + 1; second < n; second++ {
			if second > first+1 && nums[second] == nums[second-1] {
				continue
			}
			sum := target - (nums[first] + nums[second])
			third, forth := second+1, n-1
			for third < forth {
				if nums[third]+nums[forth] < sum {
					third++
				} else if nums[third]+nums[forth] > sum {
					forth--
				} else {
					resTem := []int{}
					resTem = append(resTem, nums[first], nums[second], nums[third], nums[forth])
					res = append(res, resTem)
					for third < forth && nums[third] == nums[third+1] && nums[forth] == nums[forth-1] {
						third++
						forth--
					}
					third++
					forth--
					//和下面功能相同
					//for left++; left < right && nums[left] == nums[left-1]; left++ {
					//}
					//for right--; left < right && nums[right] == nums[right+1]; right-- {
					//}
				}
			}
		}
	}
	return res
}
  • left++: 在循环的开始,left 变量会递增。
  • left++::在每次循环迭代结束时,left 的值会再次递增 1。

8、赎金信——383

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

示例 1:

输入:ransomNote = “a”, magazine = “b” 输出:false
示例 2:

输入:ransomNote = “aa”, magazine = “ab” 输出:false
示例 3:

输入:ransomNote = “aa”, magazine = “aab” 输出:true

//哈希表——map
func canConstruct(ransomNote string, magazine string) bool {
	hashMap := make(map[string]int)
	for i := range magazine {
		hashMap[string(magazine[i])]++
		//fmt.Print(string(magazine[i]))
	}
	for i := 0; i < len(ransomNote); i++ {
		if hashMap[string(ransomNote[i])] > 0 {
			hashMap[string(ransomNote[i])]--
		} else {
			return false
		}
	}
	return true
}

字符串

1、反转字符串——344

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

func reverseString(s []byte) []byte {
	for i, j := 0, len(s)-1; i < len(s)/2 && j >= len(s)/2; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
	return s
}

2、反转字符串II——541

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例 1:

输入:s = “abcdefg”, k = 2 输出:“bacdfeg”
示例 2:

输入:s = “abcd”, k = 2 输出:“bacd”

//注意:go中字符串不能修改,需要转换成字节数组
func reverseBytes(s []byte) []byte {
	for i, j := 0, len(s)-1; i < len(s)/2 && j >= len(s)/2; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
	fmt.Println("sss:", string(s))
	return s
}
func reverseStr(s string, k int) string {
	sBytes := []byte(s)
	num := 2 * k
	i := 0
	for num <= len(s) {
		reverseBytes(sBytes[i : i+k])
		i = num
		num += 2 * k

	}
	lastNum := len(s) - (num - 2*k)
	if lastNum > 0 && lastNum < k {
		reverseBytes(sBytes[num-2*k:])
	} else if lastNum < 2*k && lastNum >= k {
		reverseBytes(sBytes[num-2*k : num-k])
	}
	return string(sBytes)
}

知识点:

//字符串转字节数组
sBytes := []byte(s)
//字节数组转字符串
s = string(sBytes)

3、替换数字

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 “a1b2c3”,函数应该将其转换为 “anumberbnumbercnumber”。

//方法一:定义一个新的数组接收最后的结果
func replaceNum(s []byte) string {
	var res []byte
	flag := 0
	for i := range s {
		if s[i] <= '9' && s[i] >= '0' {
			inserElement := []byte{'n', 'u', 'm', 'b', 'e', 'r'}
			res = append(append(res, s[flag:i]...), inserElement...)
			flag = i + 1
		}
	}
	res = append(res, s[flag:]...)
	return string(res)
}
//方法二:在原数组上修改
func replaceNum(s []byte) string {
	for i := 0; i < len(s); i++ {
		if s[i] <= '9' && s[i] >= '0' {
			inserElement := []byte{'n', 'u', 'm', 'b', 'e', 'r'}
			s = append(s[:i], append(inserElement, s[i+1:]...)...)
			i = i + len(inserElement) - 1
		}
	}
	return string(s)
}

知识点:

  • …是展开数组
  • 在数组中特定位置插入元素,上述方法
  • 灵活应用数组中冒号:如 arr[:3]

4、反转字符串中的单词

package main

import (
	"fmt"
	"strings"
)

func reverseWords(s string) string {
	//去除字符串两边空格
	s = strings.TrimSpace(s)
	//以空格 分割成 数组
	arr := strings.Split(s, " ")
	for i, j := 0, len(arr)-1; i < len(arr)/2 && j >= len(arr)/2; i, j = i+1, j-1 {
		arr[i], arr[j] = arr[j], arr[i]
	}
	var filteredArr []string
	//过滤arr中的空元素
	for _, str := range arr {
		if str != "" {
			filteredArr = append(filteredArr, str)
		}
	}
	res := strings.Join(filteredArr, " ")
	return res
}
func main() {
	s := "a good  example"
	fmt.Print(reverseWords(s))
	//strings.Contains(str, " ") 用于检查每个元素是否包含空格
	//fmt.Println(strings.Contains(s, " "))
}

知识点:

  • 用于检查每个元素是否包含空格,返回值是boolen
strings.Contains(str, " ") 
fmt.Println(strings.Contains(s, " "))
  • 去除字符串两边的空格
s = strings.TrimSpace(s)
  • 去除字符串中全部的空格
s = strings.ReplaceAll(s, " ", "")
  • 以空格 分割成 数组
arr := strings.Split(s, " ")

5、找出字符串中第一个匹配项的下标——28

  • 暴力解法
// 暴力匹配 复杂度:O(m*n)
func strStr(haystack string, needle string) int {
	len1 := len(haystack)
	len2 := len(needle)
	if len1 < len2 {
		return -1
	}
	flag := 1
	i, j := 0, 0
	for i < len1 {
		for j < len2 && i < len1 {
			if haystack[i] == needle[j] {
				i++
				j++
			} else {
				j = 0
				i = flag
				break
			}
		}
		if j == len2 {
			return flag - 1
		}
		flag++

	}
	return -1
}
  • KMP算法(理解不透彻)
func strStr(haystack, needle string) int {
	n, m := len(haystack), len(needle)
	if m == 0 {
		return 0
	}
	//求next数组
	pi := make([]int, m)
	for i, j := 1, 0; i < m; i++ {
		for j > 0 && needle[i] != needle[j] {
			j = pi[j-1]
		}
		if needle[i] == needle[j] {
			j++
		}
		pi[i] = j
	}
	fmt.Println(pi)
	//根据next回退
	for i, j := 0, 0; i < n; i++ {
		for j > 0 && haystack[i] != needle[j] {
			j = pi[j-1]
		}
		if haystack[i] == needle[j] {
			j++
		}
		if j == m {
			return i - m + 1
		}
	}
	return -1
}

6、 重复的子字符串

  • 暴力枚举
//检测传过来的part子串是否可以组成s
func match(s, part string) bool {
	i := len(part)
	j := 0
	if len(part) > len(s)/2 {
		return false
	}
	for i < len(s) {
		flag := i
		for j < len(part) && i < len(s) {
			if s[i] != part[j] {
				return false
			}
			j++
			i++
		}
		if i == len(s) && j < len(part) {
			return false
		}
		j = 0
		i = flag + len(part)
	}

	return true
}
func repeatedSubstringPattern(s string) bool {
	i := 0
	var res []bool
	for i < len(s)/2 {
		part := s[:i+1]
		res = append(res, match(s, part))
		i++
	}
	fmt.Println(res)
	for k := range res {
		if res[k] == true {
			return true
		}
	}
	return false
}
  • KMP解法

贪心

1、分发饼干——455

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

示例 1:

输入: g = [1,2,3], s = [1,1] 输出: 1 解释: 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 所以你应该输出1。

示例 2:

输入: g = [1,2], s = [1,2,3] 输出: 2 解释: 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。 所以你应该输出2.

//优先满足胃口最大的孩子
func findContentChildren(g []int, s []int) int {
	sort.Ints(g)
	sort.Ints(s)
	count := 0
	i, j := len(g)-1, len(s)-1
	for i >= 0 && j >= 0 {
		if s[j] >= g[i] {
			i--
			j--
			count++
		} else {
			i--
		}
	}
	return count
}

2、摆动序列——376

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。

相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

示例 1:

输入:nums = [1,7,4,9,2,5] 输出:6 解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3)
示例 2:

输入:nums = [1,17,5,10,13,15,10,5,16,8] 输出:7 解释:这个序列包含几个长度为 7 摆动序列。
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8)

//贪心
func wiggleMaxLength(nums []int) int {
	if len(nums) == 1 {
		return len(nums)
	}
	if len(nums) == 2 && nums[0] != nums[1] {
		return 2
	}
	preNum := 0
	curNum := 0
	res := 1
	for i := 0; i < len(nums)-1; i++ {
		curNum = nums[i+1] - nums[i]
		if (preNum >= 0 && curNum < 0) || (preNum <= 0 && curNum > 0) {
			res++
			preNum = curNum
		}
	}
	return res
}

3、最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:

输入:nums = [1] 输出:1
示例 3:

输入:nums = [5,4,-1,7,8] 输出:23

  • 暴力(复杂度太大 超时)
// 暴力
func sum(num []int) int {
	res := 0
	for i := range num {
		res += num[i]
	}
	return res
}

func maxSubArray(nums []int) int {
	if len(nums) == 1 {
		return nums[0]
	}
	i := 0
	var res []int
	for i < len(nums) {
		j := i + 1
		for j <= len(nums) {
			res = append(res, sum(nums[i:j]))
			j++
		}
		i++
	}
	fmt.Println(res)
	sort.Ints(res)
	return res[len(res)-1]
}
  • 贪心:
    • 遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。
    • 当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
func maxSubArray(nums []int) int {
	count := 0
	maxNum := math.MinInt
	for i := 0; i < len(nums); i++ {
		count += nums[i]
		if count > maxNum {
			maxNum = count
		}
		if count <= 0 {
			count = 0
		}
	}
	return maxNum
}
  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值