Go 每周一刷1.0

简介: Go 每周一刷1.0

Leetcode 704


1668490742024.jpg

这是一道最典型的二分基础题,从一个有序集合中查找目标值,还不需要考虑元素重复问题,那么就简单了。

func search(nums []int, target int) int {
  left, right := 0, len(nums)-1
  var mid int
  for left <= right {
    // mid = (left + right) / 2
    // 获取中位数
    mid = left + ((right - left) >> 1)
    // 如果中位数的值等于目标值,找到了,直接返回
    if nums[mid] == target {
      return mid
      // 如果当前中位数的值 > 目标值,说明值只可能存在中位数的左区间,
      // 并且不包括中位数
    } else if nums[mid] > target {
      right = mid - 1
      // 否则当前中位数的值 < 目标值,说明值只可能存在中位数的右区间,
      // 并且不包括中位数
    } else { 
      left = mid + 1
    }
  }
  return -1
}


值得注意的是求中位数的时候如果只是单纯的 mid = (left + right) / 2 ,那么当数字过大时相加会造成溢出,因此这里直接使用位运算。

上面的代码还不是很严谨,比如说,开头过个滤。

if len(nums) == 0 {
    return -1
  }

另外值得讨论的一点是 left <= right不少人会在这上面纠结到底是 < 还是 <=。这是因为理解的角度不同,就会有大同小异的解法,就会产生差异化的代码。只要能理解边界的问题,那么咋么写都不重要。但是我依然觉得,好的代码不单单是多么精简和高级的技巧,而是简单易懂。

leftright都是数组的下标,他们代表的是当前查找的范围区间。在程序中通过判断的结果,来更新接下来要查找的区间是往左区间缩小还是右区间缩小。

那什么时候结束呢?

第一,程序已经找到结果了,那当然直接运行结束。

第二,没找到结果,不断的缩小区间,最后这个区间已经缩小成 0,没区间值了,也结束了。

现在你明白上面为什么要 <= 了吧。首先 left 肯定是不能大于 right 的,比如 [5,4] 这能是一个正常区间嘛。至于 = ,道理也很简单,[5,5] 这个区间还有一个公共的 5,如果漏掉,会导致程序出错。


Leetcode 34


1668490958390.jpg

这道题比刚才难度提高了一点,同样是查找目标值位置,我们需要返回两个值,一个值是目标值出现的第一个位置以及目标值出现的最后一个位置。

那我们上面还能用嘛?

改改就能用!

本质上对左右区间缩小的判断还是一样的道理。唯一不同的是,之前我们在查找到目标值之后就返回结果,现在不行了。我们得进一步确认目标值是不是对应第一个和最后一个的位置。

func searchRange(nums []int, target int) (res []int) {
  return append([]int{}, findFirstIndex(nums, target), findLastIndex(nums, target))
}
// 查找元素第一个
func findFirstIndex(nums []int, target int) int {
  var mid int
  left, right := 0, len(nums)-1
  for left <= right {
    //如果数字大会造成溢出
    // mid = (left + right)/2 
    //使用位运算
    mid = left + ((right - left) >> 1)
    // 如果当前中位数的值比目标值大,说明目标值只可能存在中位数的左区间(不包括中位数)
    if nums[mid] > target {
      right = mid - 1
      // 如果当前中位数的值比目标值小,说明目标值可能只可能存在中位数的右区间
    } else if nums[mid] < target {
      left = mid + 1
    } else { //说明 此时中位数的值等于目标值,但是不能确定它就是相同目标值的第一个
      //在相等的情况下,如果当前中位数索引处是0,或者当前中位数上一个索引位置的值不等于目标值,那肯定就它了,程序结束
      if mid == 0 || (nums[mid-1] != target) {
        return mid
      } else { //否则的话 肯定在左边,就往左区间再挤挤
        right = mid - 1
      }
    }
  }
  // 如果都没找到,那就返回-1
  return -1
}
// 查找元素最后一个
func findLastIndex(nums []int, target int) int {
  var mid int
  left, right := 0, len(nums)-1
  for left <= right {
    mid = left + ((right - left) >> 1)
    if nums[mid] > target {
      right = mid - 1
    } else if nums[mid] < target {
      left = mid + 1
    } else { //说明 此时中位数的值等于目标值,但是不能确定它就是相同目标值的最后一个
      //在相等的情况下,如果当前中位数索引处于最后一个位置,或者当前中位数下一个索引位置的值不等于目标值,那肯定就它了,程序结束
      if mid == len(nums)-1 || nums[mid+1] != target {
        return mid
      } else { //否则的话,肯定再右边 就往右区间再挤挤
        left = mid + 1
      }
    }
  }
  // 如果都没找到,那就返回-1 
  return -1
}

这期的题目就到这了,你有不一样的解法嘛?那么欢迎留言告诉我。代码放在:https://github.com/wuqinqiang/LeetCode-Go-Week。

相关文章
|
4月前
|
传感器 Go C语言
Go 围炉札记
Go 围炉札记
54 2
|
4月前
|
人工智能 编译器 Go
Go 哪里没有做好?Rob Pike 深刻反思了
Go 哪里没有做好?Rob Pike 深刻反思了
|
7月前
|
Java Linux Go
关于我想写一个Go系列的这件事
本文是Go语言专栏的开篇,作者sharkChili分享了他对Go语言的喜爱,并简要介绍了如何在Windows和Linux上搭建Go环境。文章包括下载安装包、解压、配置环境变量等步骤。此外,还展示了编写并运行第一个&quot;Hello, sharkChili&quot;的Go程序。最后提到了Go项目的`.gitignore`文件示例,并鼓励读者关注作者的公众号以获取更多Go语言相关的内容。
45 0
|
7月前
|
Kubernetes Go 数据库
分享48个Go源码,总有一款适合您
分享48个Go源码,总有一款适合您
279 0
go常用包总结(一) 青训营
go常用包总结(一) 青训营
|
安全 Go
go常用包总结(二) 青训营
go常用包总结(二) 青训营
|
Java 测试技术 Go
送给学Go或者转Go同学的一套编码规范
有没有 xd 们是从别的语言转 Go
191 0
送给学Go或者转Go同学的一套编码规范
|
算法 Java Go
Go可以无限Go?回家等通知吧
Go可以无限Go?回家等通知吧
|
算法 Go 索引
Go 每周一刷1.1
Go 每周一刷1.1
99 0
Go 每周一刷1.1
Go好玩的面试题之回文判断
回文,汉语词语,指汉语中的回文语法,即把相同的词汇或句子,在下文中调换位置或颠倒过来,产生首尾回环的情况,叫做回文,也叫回环。
162 0
Go好玩的面试题之回文判断