768. 最多能完成排序的块 II

62 阅读1分钟

题目:
给你一个整数数组 arr 。

将 arr 分割成若干  ,并将这些块分别进行排序。之后再连接起来,使得连接的结果和按升序排序后的原数组相同。

返回能将数组分成的最多块数?
算法:
方法一:单调栈
思路:

  1. 如果新遍历到的数字x,大于等于上一个区块的最大值maxVal,则可以组成新的区块。
  2. 如果新遍历到的数字x,小于上一个区块的最大值maxVal,则只能加入原有的区块。

用一个单调栈stack保存每个区块的最大值,如果:
1.x > maxVal,则将x加入stack,意味着找到了一个新的区块。
2.x < maxVal,则将stack中所有小于x的数出栈,因为x的出现他们不构成区块,x也不入栈。
最后stack的长度就是区块数。

func maxChunksToSorted(arr []int) int {
    stack := make([]int, 0)
    for _, x := range arr {
        if len(stack) == 0 || stack[len(stack) - 1] <= x {
            stack = append(stack, x)
        } else {
            maxVal := stack[len(stack) - 1]
            stack = stack[:len(stack) - 1]
            for len(stack) != 0 && x < stack[len(stack) - 1]  {
                stack = stack[:len(stack) - 1]
            }
            stack = append(stack, maxVal)
        }
    }
    return len(stack)
}

方法二:hash表
思路:将arr排序得到sortedArr。 如果arr[0:i]各个元素的频率和sortedArr[0:i]的频率相同,那么则i这个位置可以划分一个区块

func maxChunksToSorted(arr []int) int {
    sortedArr := make([]int, len(arr))
    copy(sortedArr, arr)
    sort.Ints(sortedArr)
    cnt := make(map[int]int)
    count := 0
    for i := range arr {
        cnt[arr[i]] ++

        cnt[sortedArr[i]] --
        equal := true
        for _, c := range cnt {
            if c != 0 {
                equal = false
                break
            }
        }
        if equal {
            count ++
        }
    }
    return count
}

优化:

func maxChunksToSorted(arr []int) int {
    sortedArr := make([]int, len(arr))
    copy(sortedArr, arr)
    sort.Ints(sortedArr)
    cnt := make(map[int]int)
    count := 0
    for i := range arr {
        cnt[arr[i]] ++
        if cnt[arr[i]]  == 0 {
            delete(cnt, arr[i])
        }
        cnt[sortedArr[i]] --
        if cnt[sortedArr[i]]  == 0 {
            delete(cnt, sortedArr[i])
        }
        if len(cnt) == 0 {
            count ++
        }
    }
    return count
}

方法三:最大值最小值
思路:num和num左边的最大值,小于右边的最小值,num这个点就可以分割一个块

func maxChunksToSorted(arr []int) int {
    leftMax, rightMin := make([]int, len(arr)), make([]int, len(arr))
    // leftMax i和i的左边的最大值
    // rightMin i右边的最小值
    count := 0 
    leftMax[0] = arr[0]
    for i := 1; i < len(arr); i ++ {
        leftMax[i] = max(arr[i], leftMax[i - 1])
    }
    rightMin[len(arr) - 1] = math.MaxInt32
    for i := len(arr) - 2; i >= 0 ; i -- {
        rightMin[i] = min(arr[i + 1], rightMin[i + 1])
    }
    for i := range leftMax {
        if leftMax[i] <= rightMin[i] {
            count ++
        }
    }
    return count
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}