315.计算右侧小于当前元素的个数

119 阅读2分钟

题目:
给你一个整数数组 nums **,按要求返回一个新数组 counts **。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。
算法:
方法一:有序数组+二分查找
从右往左遍历nums,每遍历到一个数val,从有序数组array中查找小于val的元素个数,然后将val插入array中。
该方法会超时。

func countSmaller(nums []int) []int {
	array := make([]int, len(nums))
	ans := make([]int, len(nums))
	maxPos := 0
	var insert func(array []int, index, val int)
	insert = func(array []int, index, val int) {
		for i := maxPos - 1; i >= index + 1; i -- {
			array[i] = array[i - 1]
		}
		array[index] = val
	}
	for i := len(nums) - 1; i >= 0; i -- {
		pos := find(array, nums[i], 0, maxPos)
		ans[i] = pos
		maxPos ++
		// fmt.Println("insert val:",nums[i], "right:", maxPos, "pos:", pos, array)
		insert(array, pos, nums[i])
	}
	return ans
}

// 找到第一个大于等于val的位置
func find(sortedArray []int, val, left, right int) int {
	for left < right {
		mid := (left + right) / 2
		if sortedArray[mid] < val {
			left = mid + 1
		} else {
			if mid == left || mid != left && sortedArray[mid - 1] < val {
				return mid
			} else {
				right = mid - 1
			}
		}
	}
	return right
}

方法二: 归并排序

func countSmaller(nums []int) []int {
	ans := make([]int, len(nums))
	array := make([][]int, len(nums))
	for i := range nums {
		array[i] = []int{nums[i], i}
	}
	var mergeSort func(numsIndex [][]int, left, right int)
	mergeSort = func(numsIndex [][]int, left, right int){
		if left >= right {
			return 
		}
		// tmp是逆序存储的
		tmp := make([][]int, 0)
		mid := left + (right - left) / 2
		mergeSort(numsIndex, left, mid)
		// fmt.Println("sort", left, mid, numsIndex)
		mergeSort(numsIndex, mid + 1, right)
		// fmt.Println("sort", mid + 1, right, numsIndex)
		leftPos, rightPos := mid, right

		for leftPos >= left && rightPos >= mid + 1 {
			if numsIndex[leftPos][0] > numsIndex[rightPos][0] {
				ans[numsIndex[leftPos][1]] = ans[numsIndex[leftPos][1]] + rightPos - (mid + 1) + 1
				tmp = append(tmp, numsIndex[leftPos])
				leftPos --
			} else {
				tmp = append(tmp, numsIndex[rightPos])
				rightPos --
			}
		}
		for leftPos >= left {
			tmp = append(tmp, numsIndex[leftPos])
			leftPos --
		}

		for rightPos >= mid + 1 {
			tmp = append(tmp, numsIndex[rightPos])
			rightPos --
		}

		// tmp是逆序存储的
		for index := 0; index < len(tmp); index ++ {
			numsIndex[right - index] = tmp[index]
		}	
	}
	mergeSort(array, 0, len(nums) - 1)
	return ans
}

方法三:树状数组

func reversePairs(nums []int) int {
    tmp := make([]int, len(nums))
    copy(tmp, nums)
    sort.Ints(tmp)
    // 离散化, nums保存的新值是旧值的相对大小(即排序后的索引+1)
    for i := range nums {
        nums[i] = sort.SearchInts(tmp, nums[i]) + 1
    }
    biTree := binaryIndexTree{tree:make([]int, len(nums) + 1), n: len(nums)}
    ans := 0
    // 从右往左遍历nums,小于nums[i]的数会在bitree的左侧
    for i := len(nums) - 1; i >=0; i -- {
        ans = ans + biTree.query(nums[i] - 1)
        biTree.update(nums[i])
    }
    return ans
}


type binaryIndexTree struct {
    tree []int
    n int
}

// lowbit找到最低位的1.
// lowbit的值相同,则在binary index tree的同一层
func (b binaryIndexTree) lowbit(x int) int {
    return x & -x
}

func (b binaryIndexTree) query(x int) int {
    ans := 0
    // [5](0110)-[1]lowbit(5) = 4
    // ans加上离散值为5的数的个数
    // [4](0100)-[4]lowbit(4) = 0
    // ans加上离散值小于等于4的数的个数
    for x > 0 {
        ans = ans + b.tree[x]
        x = x - b.lowbit(x)
    }
    return ans
}

func (b binaryIndexTree) update(x int) {
    for x <= b.n {
        b.tree[x] ++
        x = x + b.lowbit(x)
    }
}