GO算法-二分法

一:二分查找

 

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。


示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

func search(nums []int, target int) int {
    /**
    分析思路:
    首先看题意:有序查找,可以用二分,极端情况考虑只传一个的情况
    **/

    //开始
    //left right为左右两个
    n := len(nums)
    left := 0
    //数组下标为n-1
    right := n - 1



    //1:先写循环主干
    for left <= right {
        mid := (right + left)/2

        if nums[mid] == target {
            return mid
        } else if nums[mid] > target {
            //在右边
            right = mid - 1
        } else {
            left = mid + 1
        }
    }

    return -1
}

二:搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2
示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1
示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

func searchInsert(nums []int, target int) int {
    /**
    思路分析:
    第一部分就是个二分查找
    第二部分,不存在就插入到指定位置,每一次和中间值比较有3种情况,=,>, <,当进行到最后一轮时,如果大于,那mid+1就是他的插入位置,小于就是mid-1
    **/

    //开始

    n := len(nums)
    left := 0
    right := n -1
    //记录要插入的位置
    tag := 0

    //1:先写主体循环
    for left <= right {
        mid := (left + right) / 2
        fmt.Println(nums[mid],mid, left, right)

        if nums[mid] == target {
            return mid
        } else if target > nums[mid] {
            left = mid + 1
            //右边插入需要mid+1
            tag = left
        } else {
            right = mid -1
            //左边插入就是在mid
            tag = mid
        }
    }

    return tag
}

三:最长增长子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

 
示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1

思路在代码注释中(动态规划解法)

func lengthOfLIS(nums []int) int {
    /**
    思路分析:
    这里需要求解的是,到终点最长的子序列,如果我们能记录下前面每个点到终点的最长值,最终筛选出最长的一个就可以了。所以可以理解为,到1最长的值,到2最长的值。。。。到n最长的值。那么怎么获取每一个最大的值那,到i的最大值取决于,到前面i-1的最大值,与到i的最大值,哪个大就取哪个,所以每次有一个比较,筛选最大值。这样就可以通过动态规划来解决了。
    **/

    //开始
    n := len(nums)
    if n == 0 {
        return 0
    }
    //定义dp
    var dp = make([]int, n)

    //1:先写循环主体
    for i:=0; i < n; i++ {
        //因为dp[i]刚开始遍历到i,还么有赋值,所以默认是1
        dp[i] = 1

        //j从0开始直到匹配到最后一个,也就是i
        for j:=0; j < i; j++ {
            //nums[j] < nums[i],说明这俩符合递增
            if nums[i] > nums[j] {
                //这一步比较难理解:
                //我们先思考dp[i]等于什么,当刚进入这一层时,dp[i] = 1,初始值.
                //然后思考dp[j]等于什么,如果此刻 j = 2, 就是思考dp[2]等于什么,当i = 3时,dp[2]就是上一轮的最大值,举个例子: 1,2,3 这里dp[2] = 3最长距离,并且nums[j] = nums[2] = 3目前最大,所以nums[i]=nums[3] > 3,这个最长序列就可以加1,所以只需要比较目前最大,和当前dp[i]哪个大,取哪个就可以了。
                dp[i] = max(dp[i], dp[j]+1)
            }
        } 
    }

    //返回dp中最大的一个,这里每一次要拿最新值和最大值比较
    maxNum := dp[0]
    for i:= 1; i< len(dp); i++{
        maxNum = max(dp[i], maxNum)
    }

    return maxNum
}

func max(a, b int) int {
    if a > b {
        return a
    }

    return b
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值