leetcode 第 164 场周赛

5271. 访问所有点的最小时间

题目描述

平面上有 n 个点,点的位置用整数坐标表示 points[i] = [xi, yi]。请你计算访问所有这些点需要的最小时间(以秒为单位)。

你可以按照下面的规则在平面上移动:

  • 每一秒沿水平或者竖直方向移动一个单位长度,或者跨过对角线(可以看作在一秒内向水平和竖直方向各移动一个单位长度)。
  • 必须按照数组中出现的顺序来访问这些点。

示例 1:

img

输入:points = [[1,1],[3,4],[-1,0]]
输出:7
解释:一条最佳的访问路径是: [1,1] -> [2,2] -> [3,3] -> [3,4] -> [2,3] -> [1,2] -> [0,1] -> [-1,0]   
从 [1,1] 到 [3,4] 需要 3 秒 
从 [3,4] 到 [-1,0] 需要 4 秒
一共需要 7 秒

示例 2:

输入:points = [[3,2],[-2,2]]
输出:5

提示:

  • points.length == n
  • 1 <= n <= 100
  • points[i].length == 2
  • -1000 <= points[i][0], points[i][1] <= 1000

Tag

  • 可跨对角线移动,即可在一秒内向水平和竖直方向各移动一个单位长度,所以两点之间移动最少时间为 m a x { d x , d y } max \{dx, dy\} max{dx,dy}
  • 时间: O ( n ) O(n) O(n),空间: O ( 1 ) ​ O(1)​ O(1)

Code

go version

func minTimeToVisitAllPoints(points [][]int) int {
    minTime := 0
    for i := 0; i < len(points)-1; i++ {
        dx := points[i][0]-points[i+1][0]
        dy := points[i][1]-points[i+1][1]
        if dx < 0 {
            dx = ^dx + 1
        }
        if dy < 0 {
            dy = ^dy + 1
        }
        minTime += max(dx, dy)
    }
    return minTime
}

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

5272. 统计参与通信的服务器

题目描述

这里有一幅服务器分布图,服务器的位置标识在 m * n 的整数矩阵网格 grid 中,1 表示单元格上有服务器,0 表示没有。

如果两台服务器位于同一行或者同一列,我们就认为它们之间可以进行通信。

请你统计并返回能够与至少一台其他服务器进行通信的服务器的数量。

示例 1:

img

输入:grid = [[1,0],[0,1]]
输出:0
解释:没有一台服务器能与其他服务器进行通信。

示例 2:

img

输入:grid = [[1,0],[1,1]]
输出:3
解释:所有这些服务器都至少可以与一台别的服务器进行通信。

示例 3:

img

输入:grid = [[1,1,0,0],[0,0,1,0],[0,0,1,0],[0,0,0,1]]
输出:4
解释:第一行的两台服务器互相通信,第三列的两台服务器互相通信,但右下角的服务器无法与其他服务器通信。

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m <= 250
  • 1 <= n <= 250
  • grid[i][j] == 0 or 1

Tag

  • 某单元格有服务器,且所在行或列服务器数大于1,则 c n t + 1 cnt + 1 cnt+1
  • 时间: O ( m ∗ n ) ​ O(m*n)​ O(mn),空间: O ( n + m ) ​ O(n + m)​ O(n+m)

Code

go version

func countServers(grid [][]int) int {
    // exists := make([][]bool, len(grid))
    // for i := 0; i < len(grid); i++ {
    //     exists[i] = make([]bool, len(grid[0]))
    // }
    row := make([]int, len(grid)) 
    col := make([]int, len(grid[0]))
    cnt := 0
    for i := 0; i < len(grid); i++ {
        for j := 0; j < len(grid[0]); j++ {
            if grid[i][j] == 1 {
                row[i] += 1
                col[j] += 1
            }
        }
    }
    for i := 0; i < len(grid); i++ {
        for j := 0; j < len(grid[0]); j++ {
            if grid[i][j] == 1 && (row[i] > 1 || col[j] > 1) { // 定义
                cnt += 1
            }
        }
    }
    return cnt
}

5273. 搜索推荐系统

题目描述

给你一个产品数组 products 和一个字符串 searchWordproducts 数组中每个产品都是一个字符串。

请你设计一个推荐系统,在依次输入单词 searchWord 的每一个字母后,推荐 products 数组中前缀与 searchWord 相同的最多三个产品。如果前缀相同的可推荐产品超过三个,请按字典序返回最小的三个。

请你以二维列表的形式,返回在输入 searchWord 每个字母后相应的推荐产品的列表。

示例 1:

输入:products = ["mobile","mouse","moneypot","monitor","mousepad"], searchWord = "mouse"
输出:[
["mobile","moneypot","monitor"],
["mobile","moneypot","monitor"],
["mouse","mousepad"],
["mouse","mousepad"],
["mouse","mousepad"]
]
解释:按字典序排序后的产品列表是 ["mobile","moneypot","monitor","mouse","mousepad"]
输入 m 和 mo,由于所有产品的前缀都相同,所以系统返回字典序最小的三个产品 ["mobile","moneypot","monitor"]
输入 mou, mous 和 mouse 后系统都返回 ["mouse","mousepad"]

示例 2:

输入:products = ["havana"], searchWord = "havana"
输出:[["havana"],["havana"],["havana"],["havana"],["havana"],["havana"]]

示例 3:

输入:products = ["bags","baggage","banner","box","cloths"], searchWord = "bags"
输出:[["baggage","bags","banner"],["baggage","bags","banner"],["baggage","bags"],["bags"]]

示例 4:

输入:products = ["havana"], searchWord = "tatiana"
输出:[[],[],[],[],[],[],[]]

提示:

  • 1 <= products.length <= 1000
  • 1 <= Σ products[i].length <= 2 * 10^4
  • products[i] 中所有的字符都是小写英文字母。
  • 1 <= searchWord.length <= 1000
  • searchWord 中所有字符都是小写英文字母。

Tag

  • 每次匹配后的列表作为新的列表遍历,同时注意字符比较时越界问题,以及隐藏的一个坑(见代码)
  • 时间: O ( l e n ( s e a r c h W o r d ) ∗ O(len(searchWord)* O(len(searchWord) ∑ l e n ( p r o d u c t [ i ] ) \sum len(product[i]) len(product[i]) ) ) ),空间: O ( O( O( ∑ l e n ( p r o d u c t [ i ] ) ) \sum len(product[i])) len(product[i]))

Code

go version

func suggestedProducts(products []string, searchWord string) [][]string {
    ans := [][]string{}
    toMatch := products // 新的切片对象(不使用copy)
    sorted := false
    for i, character := range searchWord {
        curMatch := []string{}
        for _, product := range toMatch {
            if i < len(product) && rune(product[i]) == character { // byte转化为rune
                curMatch = append(curMatch, product)
            }
        }
        toMatch = curMatch // 更新下一次匹配的列表
        if !sorted { // 坑:case实际要求推荐产品不超过3时也按字典序返回
            sort.Strings(curMatch) // 字典序排序
            sorted = true
        }
        if len(curMatch) > 3 {
            // sort.Strings(curMatch) // 字典序排序
            curMatch = curMatch[0:3] // 字典序最小的三个产品
        }
        ans = append(ans, curMatch) // 每次获得一个推荐列表(切片数组)
    }
    
    return ans
}

5274. 停在原地的方案数

题目描述

有一个长度为 arrLen 的数组,开始有一个指针在索引 0 处。

每一步操作中,你可以将指针向左或向右移动 1 步,或者停在原地(指针不能被移动到数组范围外)。

给你两个整数 stepsarrLen ,请你计算并返回:在恰好执行 steps 次操作以后,指针仍然指向索引 0 处的方案数。

由于答案可能会很大,请返回方案数 10^9 + 7 后的结果。

示例 1:

输入:steps = 3, arrLen = 2
输出:4
解释:3 步后,总共有 4 种不同的方法可以停在索引 0 处。
向右,向左,不动
不动,向右,向左
向右,不动,向左
不动,不动,不动

示例 2:

输入:steps = 2, arrLen = 4
输出:2
解释:2 步后,总共有 2 种不同的方法可以停在索引 0 处。
向右,向左
不动,不动

示例 3:

输入:steps = 4, arrLen = 2
输出:8

提示:

  • 1 <= steps <= 500
  • 1 <= arrLen <= 10^6

Tag

  • d p [ i ] [ j ] dp[i][j] dp[i][j]: 指针移动 j j j 步最终到达索引 i i i 的方案数,由于指针有向左、向右、不动三种选择,则:

d p [ i ] [ j ] = { d p [ i ] [ j − 1 ] + d p [ i + 1 ] [ j − 1 ] i f    i = 0 d p [ i ] [ j − 1 ] + d p [ i − 1 ] [ j − 1 ] i f    i = l e n − 1 d p [ i ] [ j − 1 ] + d p [ i + 1 ] [ j − 1 ] + d p [ i − 1 ] [ j − 1 ] o t h e r s dp[i][j] =\begin{cases} dp[i][j-1] + dp[i+1][j-1] & if~~i = 0 \\ dp[i][j-1] + dp[i-1][j-1] & if~~i = len-1 \\ dp[i][j-1] + dp[i+1][j-1] + dp[i-1][j-1] & others \end{cases} dp[i][j]=dp[i][j1]+dp[i+1][j1]dp[i][j1]+dp[i1][j1]dp[i][j1]+dp[i+1][j1]+dp[i1][j1]if  i=0if  i=len1others

  • 优化-——时间: O ( min ⁡ ( s t e p s / 2 + 1 , a r r L e n ) ∗ s t e p s ) O(\min(steps/2+1, arrLen)*steps) O(min(steps/2+1,arrLen)steps),空间: O ( min ⁡ ( s t e p s / 2 + 1 , a r r L e n ) ∗ s t e p s ) O(\min(steps/2+1, arrLen)*steps) O(min(steps/2+1,arrLen)steps)

Code

go version

const P = 1e9 + 7
func numWays(steps int, arrLen int) int {
   if min(steps/2+1, arrLen) == 1 {
       return 1
   }
	// dp数组的第一维不能超过steps/2+1,否则无法返回原索引点0
    dp := make([][]int, min(steps/2+1, arrLen)) 
    for i := 0; i < len(dp); i++ {
        dp[i] = make([]int, steps+1)
    }

    dp[0][0] = 1 // dp[1...][0] = 0
    for j := 1; j <= steps; j++ {
        dp[0][j] = (dp[0][j-1] + dp[1][j-1])%P
        for i := 1; i < len(dp)-1; i++ {
            dp[i][j] = ((dp[i][j-1] + dp[i+1][j-1])%P + dp[i-1][j-1])%P
        }
        dp[len(dp)-1][j] = (dp[len(dp)-1][j-1] + dp[len(dp)-2][j-1])%P
    }

    return dp[0][steps]
}

func min(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、付费专栏及课程。

余额充值