Algorithm Binary Search

记录 Binary Search 的算法实现

“33. Search in Rotated Sorted Array” Golang

func search(nums []int, target int) (ret int) {
    if len(nums) == 0 {
        return -1
    }
    //defer func(){ fmt.Println(nums[0], nums[len(nums)-1], ret) }()
    mid := len(nums)>>1

    if nums[0] <= nums[len(nums)-1] {
        if target > nums[len(nums)-1] || target < nums[0] {
            return -1
        } else if target == nums[mid] {
            return mid
        }
    }

    if ret = search(nums[:mid], target); ret != -1 {
        return ret
    } else if ret = search(nums[mid:], target); ret != -1 {
        return mid + ret
    }

    return -1
}

“34. Find First and Last Position of Element in Sorted Array” Golang

  • 可以利用sort.SearchInts(a []int, x int) int,用二分查找找到元素第一次出现的下标,如果没有找到则返回元素插入操作的下标
func searchRange(nums []int, target int) []int {
    l := sort.SearchInts(nums, target)
    if l == len(nums) || nums[l] != target {
        return []int{-1, -1}
    }
    r := sort.SearchInts(nums, target + 1) - 1
    return []int{l, r}
}

“81. Search in Rotated Sorted Array II”

func search(nums []int, target int) bool {
    n := len(nums)
    if n == 1 {
        return nums[0] == target
    }
    for l, r := 0, n-1; l <= r; {
        mid := (l+r)>>1
        if nums[mid] == target {
            return true
        } else if nums[l] == nums[mid] && nums[mid] == nums[r] {
            l, r = l+1, r-1
        } else if nums[l] <= nums[mid] {
            if nums[l] <= target && target < nums[mid] {
                r = mid-1
            } else {
                l = mid+1
            }
        } else {
            if nums[mid] < target && target <= nums[r] {
                l = mid+1
            } else {
                r = mid-1
            }
        }
    }
    return false
}

“162. Find Peak Element”

func findPeakElement(nums []int) int {
    n := len(nums)
    compare := func(pos int, toLeft bool) (isUpper bool) {
        if pos == 0 || pos == n-1 {
            return true
        }
        if toLeft {
            return nums[pos] > nums[pos-1]
        }
        return nums[pos] > nums[pos+1]
    }

    l, r := 0, n-1
    for l + 1 < r {
        m := (l+r)>>1
        lUp, rUp := compare(m, true), compare(m, false)
        if lUp && rUp {
            return m
        } else if lUp && !rUp {
            l = m
        } else {
            r = m
        }
    }
    if l != r {
        if nums[l] > nums[r] {
            return l
        } else {
            return r
        }
    }
    return l
}

“275. H-Index II”

func hIndex(citations []int) int {
    n := len(citations)
    l, r := -1, n
    for l+1 < r {
        mid := (l+r)>>1
        if n-mid <= citations[mid] {
            r = mid
        } else {
            l = mid
        }
    }
    return n-r
    // 可以直接利用 sort 包提供的 LowerBound 算法:
    return n - sort.Search(n, func(x int) bool { return citations[x] >= n-x })
}

“300. Longest Increasing Subsequence”

func lengthOfLIS(nums []int) (ret int) {
    var dp []int
    for _, n := range nums {
        if idx := sort.SearchInts(dp, n); idx == len(dp) {
            dp = append(dp, n)
        } else {
            dp[idx] = n
        }
    }
    return len(dp)
}
int lengthOfLIS(vector<int>& nums) {
	vector<int> dp;
    for (auto i : nums) {
        auto it = lower_bound(dp.begin(), dp.end(), i);
        if (it == dp.end()) dp.push_back(i);
        else *it = i;
    }
    return dp.size();
}

“374. Guess Number Higher or Lower”

func guessNumber(r int) int {
    l := 0
    for l+1 < r {
        mid := (l+r)>>1
        if result := guess(mid); result == 0 {
            return mid
        } else if result == -1 {
            r = mid
        } else {
            l = mid
        }
    }
    return r
}

“673. Number of Longest Increasing Subsequence”

func findNumberOfLIS(nums []int) int {
    dp, cnt := [][]int{}, [][]int{}
    for _, v := range nums {
        i := sort.Search(len(dp), func(i int) bool { return dp[i][len(dp[i])-1] >= v })
        c := 1
        if i > 0 {
            k := sort.Search(len(dp[i-1]), func(k int) bool { return dp[i-1][k] < v })
            c = cnt[i-1][len(cnt[i-1])-1] - cnt[i-1][k]
        }
        if i == len(dp) {
            dp = append(dp, []int{v})
            cnt = append(cnt, []int{0,c})
        } else {
            dp[i] = append(dp[i], v)
            cnt[i] = append(cnt[i], cnt[i][len(cnt[i])-1] + c)
        }
    }
    c := cnt[len(cnt)-1]
    return c[len(c)-1]
}

“887. Super Egg Drop”

func superEggDrop(k int, n int) int {
    memo := make(map[int]int)
    var dfs func(int, int) int
    dfs = func(k, n int) (ans int) {
        mask := n<<8+k
        if val, exists := memo[mask]; exists {
            return val
        } else if n == 0 {
        } else if k == 1 {
            ans = n
        } else {
            l, r := 1, n
            for l+1 < r {
                mid := (l+r)>>1
                t1, t2 := dfs(k-1, mid-1), dfs(k, n-mid)
                if t1 < t2 {
                    l = mid
                } else if t1 > t2 {
                    r = mid
                } else {
                    l, r = mid, mid
                }
            }
            ans = 1 + min(max(dfs(k-1, l-1), dfs(k, n-l)), max(dfs(k-1, r-1), dfs(k, n-r)))
        }
        memo[mask] = ans
        return ans
    }
    return dfs(k, n)
}

“1011. Capacity To Ship Packages Within D Days”

func shipWithinDays(weights []int, D int) int {
    // 查找重量的左右边界
    left, right := 0, 0
    for _, w := range weights {
        if w > left {
            left = w
        }
        right += w
    }
    return left + sort.Search(right-left, func(x int) bool {
        x += left
        day, sum := 1, 0
        for _, w := range weights {
            if sum + w > x {
                day++
                sum = 0
            }
            sum += w
        }
        return day <= D
    })
}

“1713. Minimum Operations to Make a Subsequence”

func minOperations(target []int, arr []int) int {
    n := len(target)
    m := make(map[int]int, n)
    for i, t := range target {
        m[t] = i
    }
    dp := make([]int, 0, n)
    for _, x := range arr {
        if newIdx, exists := m[x]; exists {
            if idx := sort.SearchInts(dp, newIdx); idx < len(dp) {
                dp[idx] = newIdx
            } else {
                dp = append(dp, newIdx)
            }
        }
    }
    return n - len(dp)
}

“1723. Find Minimum Time to Finish All Jobs”

func minimumTimeRequired(jobs []int, k int) int {
    sort.Sort(sort.Reverse(sort.IntSlice(jobs)))
    l, r := jobs[0], 0
    for _, v := range jobs {
        r += v
    }

    return l + sort.Search(r-l, func(limit int) bool {
        limit += l
        sum := make([]int, k)

        var backtrack func(int) bool
        backtrack = func(idx int) bool {
            if idx == len(jobs) {
                return true
            }
            for i := range sum {
                if sum[i] + jobs[idx] <= limit {
                    sum[i] += jobs[idx]
                    if backtrack(idx+1) {
                        return true
                    }
                    sum[i] -= jobs[idx]
                }
                if sum[i]+jobs[idx]==limit || sum[i]==0 {
                    return false
                }
            }
            return false
        }
        return backtrack(0)
    })
}

“1885. Count Pairs in Two Arrays”

func countPairs(nums1 []int, nums2 []int) (ret int64) {
    n := len(nums1)
    diff := make([]int, n)
    for i := 0; i < n; i++ {
        diff[i] = nums1[i] - nums2[i]
    }
    sort.Ints(diff)

    binarySearch := func(target, start int) int {
        if target > diff[n-1] {
            return n
        }
        l, r := start, n
        for l+1 < r {
            mid := (l+r)>>1
            if diff[mid] < target {
                l = mid
            } else {
                r = mid
            }
        }
        return r
    }

    for i := 0; i < n; i++ {
        idx := binarySearch(-diff[i]+1, i)
        ret += int64(n - idx)
    }

    return ret
}