题目:
给你一个整数数组 arr 。
将 arr 分割成若干 块 ,并将这些块分别进行排序。之后再连接起来,使得连接的结果和按升序排序后的原数组相同。
返回能将数组分成的最多块数?
算法:
方法一:单调栈
思路:
- 如果新遍历到的数字x,大于等于上一个区块的最大值maxVal,则可以组成新的区块。
- 如果新遍历到的数字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
}