IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    『代码随想录』贪心(Greedy)

    NX の 博客发表于 2023-11-28 02:59:40
    love 0

    DAY 31

    分发饼干

    遍历每块饼干,尝试将其分配给胃口最小的那个尚未满足的孩子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    func findContentChildren(g []int, s []int) int {
    sort.Ints(g)
    sort.Ints(s)
    n, m := len(g), len(s)
    i, j := 0, 0

    for i < n && j < m {
    if s[j] >= g[i] {
    i++
    }
    j++
    }
    return i
    }

    摆动序列

    直接找出山峰和山谷就行,那些山腰的元素全都不要

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    func wiggleMaxLength(nums []int) int {
    n := len(nums)
    if n < 2 {
    return n
    }

    prev := nums[1] - nums[0]
    ans := 2
    if prev == 0 {
    ans = 1
    }

    for i := 2; i < n; i++ {
    diff := nums[i] - nums[i-1]
    if diff > 0 && prev <= 0 || diff < 0 && prev >= 0 {
    ans++
    prev = diff
    }
    }
    return ans
    }

    最大子数组和

    这道题按理来说应该使用 dp,但是既然要用贪心,那就写写贪心的(

    局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    func maxSubArray(nums []int) int {
    n := len(nums)
    ans := math.MinInt
    sum := 0
    for i := 0; i < n; i++ {
    sum += nums[i]
    ans = max(ans, sum)
    if sum < 0 {
    sum = 0
    }
    }
    return ans
    }

    DAY 32

    买卖股票的最佳时机 II

    这道题照理来说也应该使用 dp (

    贪心的思想是,只要今天的价格比昨天的价格高,就假设我们昨天买入,今天卖出,从而获得利润

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    func maxProfit(prices []int) int {
    n := len(prices)
    ans := 0
    for i := 1; i < n; i++ {
    if prices[i] > prices[i-1] {
    ans += prices[i] - prices[i-1]
    }
    }
    return ans
    }

    跳跃游戏

    每一步都尽可能远更新覆盖范围

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    func canJump(nums []int) bool {
    n := len(nums)
    cover := 0
    for i := 0; i <= cover; i++ {
    cover = max(i+nums[i], cover)
    if cover >= n-1 {
    return true
    }
    }
    return false
    }

    跳跃游戏 II

    需要维护两个区间范围

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    func jump(nums []int) int {
    n := len(nums)
    curr, next, ans := 0, 0, 0

    for i := 0; i < n-1; i++ {
    next = max(nums[i]+i, next)
    if i == curr {
    curr = next
    ans++
    }
    }
    return ans
    }

    DAY 33

    周日休息

    DAY 34

    K 次取反后最大化的数组和

    尽量将负数转为正数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    func largestSumAfterKNegations(nums []int, k int) int {
    n := len(nums)
    sort.Ints(nums)

    for i := 0; i < n && nums[i] < 0 && k > 0; i, k = i+1, k-1 {
    nums[i] = -nums[i]
    }
    if k == 0 {
    return getSum(nums)
    }
    sort.Ints(nums)
    for k != 0 {
    nums[0] = -nums[0]
    k--
    }
    return getSum(nums)
    }

    func getSum(nums []int) int {
    ans := 0
    for _, val := range nums {
    ans += val
    }
    return ans
    }

    加油站

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    func canCompleteCircuit(gas []int, cost []int) int {
    n := len(gas)
    diff := make([]int, n)
    for i := 0; i < n; i++ {
    diff[i] = gas[i] - cost[i]
    }

    ans, i, sum, totalSum := 0, 0, 0, 0
    for ; i < n; i++ {
    sum += diff[i]
    totalSum += diff[i]
    if sum < 0 {
    sum = 0
    ans = i + 1
    }
    }

    if totalSum < 0 {
    return -1
    }
    return ans
    }

    分发糖果

    感觉有点像接雨水,要考虑左边也要考虑右边

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    func candy(ratings []int) int {
    n := len(ratings)
    need := make([]int, n)
    for i := 0; i < n; i++ {
    need[i] = 1
    }
    for i := 1; i < n; i++ {
    if ratings[i] > ratings[i-1] {
    need[i] = need[i-1] + 1
    }
    }
    for i := n - 2; i >= 0; i-- {
    if ratings[i] > ratings[i+1] {
    need[i] = max(need[i+1]+1, need[i])
    }
    }
    ans := 0
    for i := 0; i < n; i++ {
    ans += need[i]
    }
    return ans
    }

    DAY 35

    柠檬水找零

    • 当支付 5 时,直接收下
    • 当支付 10 时,拿 5 找零
    • 当支付 20 时,优先使用 10+5 进行找零,再使用 5+5+5
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    func lemonadeChange(bills []int) bool {
    five, ten, twenty := 0, 0, 0
    for _, bill := range bills {
    switch bill {
    case 5:
    five++
    case 10:
    five--
    ten++
    case 20:
    if ten != 0 {
    ten--
    five -= 1
    } else {
    five -= 3
    }
    twenty++
    }
    if five < 0 || ten < 0 || twenty < 0 {
    return false
    }
    }
    return true
    }

    根据身高重建队列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    func reconstructQueue(people [][]int) [][]int {
    sort.Slice(people,func(i,j int)bool{
    if people[i][0] != people[j][0]{
    return people[i][0]>people[j][0]
    }
    return people[i][1]<people[j][1]
    })
    ans:=[][]int{}
    for _,person:=range people{
    idx:=person[1]
    ans=append(ans[:idx],append([][]int{person},ans[idx:]...)...)
    }
    return ans
    }

    用最少数量的箭引爆气球

    看上去有点像合并区间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    func findMinArrowShots(points [][]int) int {
    ans:=0
    curr:=math.MinInt
    sort.Slice(points,func (i,j int)bool{
    return points[i][1]<points[j][1]
    })
    for _,point:=range points{
    if point[0]>curr{
    curr=point[1]
    ans++
    }
    }
    return ans
    }

    DAY 36

    无重叠区间

    记录有多少重叠区间即可,与上题相同

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    func eraseOverlapIntervals(intervals [][]int) int {
    n := len(intervals)
    ans, curr := 0, math.MinInt
    sort.Slice(intervals, func(i, j int) bool {
    return intervals[i][1] < intervals[j][1]
    })
    for _, interval := range intervals {
    if interval[0] >= curr {
    curr = interval[1]
    ans++
    }
    }
    return n - ans
    }

    划分字母区间

    因为要包含所有的当前字符,所以需要记录字符的最远出现位置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    func partitionLabels(s string) []int {
    m := map[rune]int{}
    for idx, c := range s {
    m[c] = idx
    }
    left, right := 0, 0
    ans := []int{}
    for idx, c := range s {
    right = max(right, m[c])
    if idx == right {
    ans = append(ans, right-left+1)
    left = right + 1
    }
    }
    return ans
    }

    合并区间

    经典题目

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    func merge(intervals [][]int) [][]int {
    sort.Slice(intervals, func(i, j int) bool {
    return intervals[i][0] < intervals[j][0]
    })
    ans := [][]int{}
    for _, interval := range intervals {
    if len(ans) > 0 && interval[0] <= ans[len(ans)-1][1] {
    ans[len(ans)-1][1] = max(ans[len(ans)-1][1], interval[1])
    } else {
    ans = append(ans, interval)
    }
    }
    return ans
    }

    DAY 37

    单调递增的数字

    从左往右遍历各位数字,找到第一个开始下降的数字,将其减一,然后后面全是 9 即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    func monotoneIncreasingDigits(n int) int {
    s := []byte(strconv.Itoa(n))
    i := 1
    for i < len(s) && s[i] >= s[i-1] {
    i++
    }
    if i < len(s) {
    for i > 0 && s[i] < s[i-1] {
    s[i-1]--
    i--
    }
    for i++; i < len(s); i++ {
    s[i] = '9'
    }
    }
    ans, _ := strconv.Atoi(string(s))
    return ans
    }

    监控二叉树

    尽量在叶子节点的父节点安装摄像头

    讲真这道题有点抽象,还是 hard(

    这道题讲真应该动态规划做



沪ICP备19023445号-2号
友情链接