前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LeetCode中级算法-排序和搜索(2)

LeetCode中级算法-排序和搜索(2)

作者头像
码农帮派
发布2021-01-12 14:55:28
2570
发布2021-01-12 14:55:28
举报
文章被收录于专栏:码农帮派码农帮派

合并区间

[题目]

给出一个区间的集合,请合并所有重叠的区间。

[输入1]

代码语言:javascript
复制
intervals = [[1,3],[2,6],[8,10],[15,18]] 

[返回1]

代码语言:javascript
复制
[[1,6],[8,10],[15,18]]

[输入2]

代码语言:javascript
复制
intervals = [[1,4],[4,5]]

[返回2]

代码语言:javascript
复制
[[1,5]]

[解法]

首先按照小范围的左边界进行升序排序,排序完成以后,遍历新的范围,可以放入合并队列的条件:

1. 合并队列中尚无元素

2. 当前遍历到的小范围的左边界要比合并队列中最后一个范围的左边界还要大

不满足上面的条件的,说明是和合并队列中最后一个范围有重合,只需要更新合并队列中最后一个范围的右边界为最大值

[代码实现]

代码语言:javascript
复制
package main

import (
  "fmt"
  "sort"
)

func main() {
  input := [][]int {{1,3},{2,6},{8,10},{15,18}}
  result := computeResult(input)
  fmt.Println("result:", result)
}

type ISort [][]int

func (sort ISort) Len() int {
  return len(sort)
}

func (sort ISort) Less(i, j int) bool {
  return sort[i][0] < sort[j][0]
}

func (sort ISort) Swap(i, j int) {
  sort[i], sort[j] = sort[j], sort[i]
}

func computeResult(input [][]int) [][]int {
  // 首先对原集合的左边界进行升序排列
  aInput := ISort{}
  for _, item := range input  {
    aInput = append(aInput, item)
  }
  sort.Sort(aInput)

  result := [][]int {}
  for i := 0; i < len(aInput); i++ {
    // 当前小范围的左右边界
    left, right := aInput[i][0], aInput[i][1]
    // 当前合并队列的长度
    resLen := len(result)
    // 直接可以放入合并队列的条件:
    // 1. 合并队列中第一个范围
    // 2. 当前小范围的左边界,要比合并队列中最后一个范围的右边界要大
    if resLen == 0 || result[resLen - 1][1] < left {
      result = append(result, []int {left, right})
    } else {
      // 选取右边界中比较大的那个更新上来
      result[resLen - 1][1] = max(result[resLen - 1][1], aInput[i][1])
    }
  }
  return resul
}

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

  return b
}

搜索旋转排序数组

[题目]

升序排列的整数数组 nums 在预先未知的某个点上进行了旋转(例如, [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] )。

请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

[输入1]

代码语言:javascript
复制
nums = [4,5,6,7,0,1,2], target = 0

[返回1]

代码语言:javascript
复制
4

[输入2]

代码语言:javascript
复制
nums = [4,5,6,7,0,1,2], target = 3

[返回2]

代码语言:javascript
复制
-1

[解法]

设置一个mid指针,通过判断数组中下标为mid的元素和左右边界以及target之间的关系,确定mid向左定界,还是想有定界,直到mid指向的元素等于target,则找到了target的下标,否则没有该元素。

此题目要求在O(logn)时间内完成搜索,所以要是用二分查找,二分查找就需要引入mid = (left + right) / 2,在这个基础上,通过判断target和左右边界的位置,确定下一轮left和right的边界位置

[代码实现]

代码语言:javascript
复制
package main

import "fmt"

func main() {
  input := []int {4,5,6,7,0,1,2}
  target := 0
  result := computeResult(target, input)
  fmt.Println("result:", result)
}

func computeResult(target int, input []int) int {
  left, right := 0, len(input) - 1
  count := len(input)
  for left <= right {
    mid := (left + right) / 2
    if input[mid] == target {
      return mid
    }

    if input[0] < input[mid] {
      // 这种情况target肯定在left和mid之间
      if input[0] <= target && target < input[mid] {
        right = mid - 1
      } else {
        left = mid + 1
      }
    } else {
      if input[mid] < target && target <= input[count - 1] {
        // 这种情况下target肯定在mid到right之间
        left = mid + 1
      } else {
        right = mid - 1
      }
    }
  }

  return -1
}

搜索二维矩阵

[题目]

升序排列的整数数组 nums 在预先未知的某个点上进行了旋转(例如, [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] )。

请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

[输入1]

代码语言:javascript
复制
matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5

[返回1]

代码语言:javascript
复制
true

[输入2]

代码语言:javascript
复制
matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20

[返回2]

false

[解法1]

每行进行二分查找, 遍历整个二维矩阵,这样时间复杂度O(nlogn)

[代码实现1]

代码语言:javascript
复制
func computeResult(target int, input [][]int) bool {
  count := len(input)
  for i := 0; i < count; i++ {
    if _compute(target, input[i]) {
      return true
    }
  }

  return false
}

func _compute(target int, input []int) bool {
  left := 0
  right := len(input) - 1
  for left <= right {
    mid := (left + right) / 2
    if input[mid] == target {
      return true
    }

    if input[mid] < target {
      left = mid + 1
    } else {
      right = mid - 1
    }
  }

  return false
}

[解法2]

从右上角开始同时移动横向和纵向的两个指针,直到找到和target相同的元素,这种算法的时间复杂度是O(m + n),但是需要注意的是,需要保证在遍历的时候两个方向的升序、降序方式是相反的,这样可以不考虑回退,即从左下角或者右上角开始向对向方向遍历,若横纵向遍历的顺序一致,那么坐标的移动将变得困难重重

[代码实现2]

代码语言:javascript
复制
func computeResult2(target int,input [][]int) bool {
  rowCount := len(input)
  colCount := len(input[0])
  rowIndex := 0
  colIndex := colCount - 1
  for rowIndex < rowCount && colIndex >= 0 {
    if target < input[rowIndex][colIndex] {
      colIndex--
    } else if target > input[rowIndex][colIndex] {
      rowIndex++
    } else {
      return true
    }
  }

  return false
}

[代码测试]

代码语言:javascript
复制
package main

import "fmt"

func main() {
  input := [][]int {
    {1,4,7,11,15},
    {2,5,8,12,19},
    {3,6,9,16,22},
    {10,13,14,17,24},
    {18,21,23,26,30},
  }
  target := 5

  result := computeResult(target, input)
  fmt.Println("result:", result)

  result2 := computeResult2(target, input)
  fmt.Println("result:", result2)
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农帮派 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档