2021-07-30:两个有序数组间相加和的Topk问题。给定两个有序数组arr1和arr2,再给定一个整数k,返回来自arr1和arr2的两个数相加和最大的前k个,两个数必须分别来自两个数组。按照降序输出。[要求]时间复杂度为O(klogk)。
福大大 答案2021-07-30:
1.左神方法。大根堆。
时间复杂度:O(klogk)。
空间复杂度:O(k)。
2.我的方法。小根堆。两个有序数组构成一个二维数组。然后从右下往左上遍历,当遍历数量大于等于k时,停止遍历。见图。
时间复杂度:略大于O(k)。
空间复杂度:O(k)。
代码用golang编写。代码如下:
package main import ( "fmt" "sort" ) func main() { arr1 := []int{1, 2, 3, 4, 5} arr2 := []int{3, 5, 7, 9, 11} topK := 4 if true { ret := topKSum1(arr1, arr2, topK) fmt.Println("左神的方法:", ret) } if true { ret := topKSum2(arr1, arr2, topK) fmt.Println("我的方法:", ret) } } type Node struct { index1 int // arr1中的位置 index2 int // arr2中的位置 sum int // arr1[index1] + arr2[index2]的值 } func NewNode(i1 int, i2 int, s int) *Node { ret := &Node{} ret.index1 = i1 ret.index2 = i2 ret.sum = s return ret } func topKSum1(arr1 []int, arr2 []int, topK int) []int { if len(arr1) == 0 || len(arr2) == 0 || topK < 1 { return nil } N := len(arr1) M := len(arr2) topK = getMin(topK, N*M) res := make([]int, topK) resIndex := 0 maxHeap := make([]*Node, 0) set := make(map[int]struct{}) i1 := N - 1 i2 := M - 1 Push(&maxHeap, NewNode(i1, i2, arr1[i1]+arr2[i2])) set[x(i1, i2, M)] = struct{}{} for resIndex != topK { curNode := Pop(&maxHeap) res[resIndex] = curNode.sum resIndex++ i1 = curNode.index1 i2 = curNode.index2 delete(set, x(i1, i2, M)) _, ok := set[x(i1-1, i2, M)] if i1-1 >= 0 && !ok { set[x(i1-1, i2, M)] = struct{}{} Push(&maxHeap, NewNode(i1-1, i2, arr1[i1-1]+arr2[i2])) } _, ok = set[x(i1, i2-1, M)] if i2-1 >= 0 && !ok { set[x(i1, i2-1, M)] = struct{}{} Push(&maxHeap, NewNode(i1, i2-1, arr1[i1]+arr2[i2-1])) } } return res } func getMin(a int, b int) int { if a < b { return a } else { return b } } func x(i1 int, i2 int, M int) int { return i1*M + i2 } func Push(maxHeap *[]*Node, node *Node) { *maxHeap = append(*maxHeap, node) } func Pop(maxHeap *[]*Node) *Node { sort.Slice(*maxHeap, func(i, j int) bool { return (*maxHeap)[i].sum < (*maxHeap)[j].sum }) ans := (*maxHeap)[len(*maxHeap)-1] *maxHeap = (*maxHeap)[0 : len(*maxHeap)-1] return ans } func topKSum2(arr1 []int, arr2 []int, topK int) []int { if len(arr1) == 0 || len(arr2) == 0 || topK < 1 { return nil } N := len(arr1) M := len(arr2) topK = getMin(topK, N*M) maxHeap := make([]int, 0) i1Start, i2Start := N-1, M-1 count := 0 for { for i1, i2 := i1Start, i2Start; i1 >= 0 && i2 < M; i1, i2 = i1-1, i2+1 { PushInt(&maxHeap, arr1[i1]+arr2[i2]) if len(maxHeap) > topK { PopInt(&maxHeap) } count++ } if count >= topK { break } if i2Start > 0 { //左移 i2Start-- } else { //上移 i1Start-- } } return maxHeap } func PushInt(maxHeap *[]int, node int) { *maxHeap = append(*maxHeap, node) } func PopInt(maxHeap *[]int) int { sort.Slice(*maxHeap, func(i, j int) bool { return (*maxHeap)[i] > (*maxHeap)[j] }) ans := (*maxHeap)[len(*maxHeap)-1] *maxHeap = (*maxHeap)[0 : len(*maxHeap)-1] return ans }
执行结果如下: