Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Published

...

不使用 map 去重 - 而是使用合并 k 个有序链表(丑数 II)的思路

Status
colourBlue
title待复习

Code Block
languagego
func nthSuperUglyNumber(n int, primes []int) int {
    h_ := make(Heap, 0, n)
    h := &h_
    
    for _, p := range primes {
        heap.Push(h, [3]int{1, p, 0})
    }
    
    uglys := make([]int, 1, n)
    uglys[0] = 1
    
    
    for len(uglys) < n {
        top := heap.Pop(h).([3]int)
        num, p, pi := top[0], top[1], top[2]
        
        if num != uglys[len(uglys) - 1] {
            uglys = append(uglys, num)
        }
        
        heap.Push(h, [3]int{p * uglys[pi], p, pi+1})
    }
    
    return uglys[n-1]
}

type Heap [][3]int

func (h Heap) Len() int           { return len(h) }
func (h Heap) Less(i, j int) bool { return h[i][0] < h[j][0] }
func (h Heap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *Heap) Push(x any) {
	*h = append(*h, x.([3]int))
}

func (h *Heap) Pop() any {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

...

Code Block
languagego
func nthUglyNumber(n int, a int, b int, c int) int {
    h := &Heap{}
    
    heap.Push(h, [2]int{a, a})
    heap.Push(h, [2]int{b, b})
    heap.Push(h, [2]int{c, c})
    
    i := 0
    num := 0
    for i < n {
        top := heap.Pop(h).([2]int)
        v, factor := top[0], top[1]
        
        if v != num {
            num = v
            i++
        }
        
        heap.Push(h, [2]int{v + factor, factor})
    }
    
    return num
}

type Heap [][2]int

func (h Heap) Len() int           { return len(h) }
func (h Heap) Less(i, j int) bool { return h[i][0] < h[j][0] }
func (h Heap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *Heap) Push(x any) {
	*h = append(*h, x.([2]int))
}

func (h *Heap) Pop() any {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

二分 + 集合解法

Status
colourBlue
title待复习

Code Block
languagego
func nthUglyNumber(n int, a int, b int, c int) int {
    L, R := 1, int(2e9) + 1
    
    // 二分:找到 [L, R) 范围内满足 f() == n 的最小值
    
    for L < R {
        mid := L + (R - L) / 2
        
        if f(mid, a, b, c) >= n {
            R = mid
        } else { // <
            L = mid + 1
        }
    }
    
    return R
}

func f(num int, a, b, c int) int {
    setA := num / a
    setB := num / b
    setC := num / c
    
    lcmAB := lcm(a, b)
    
    setAB := num / lcmAB
    setAC := num / lcm(a, c)
    setBC := num / lcm(b, c)
    
    setABC := num / lcm(lcmAB, c)
    
    return setA + setB + setC - setAB - setAC - setBC + setABC
}

func lcm(a, b int) int {
    return a * b / gcd(a, b)
}

func gcd(a, b int) int {
    // assert a <= b
    if a > b { a, b = b, a }
    
    for a != 0 {
        a, b = b % a, a
    }
    
    return b
}