【刷题】1051. 高度检查器

本文解析了LeetCode题目1051高度检查器的解题思路,通过Python和Go语言实现,并探讨了排序和计数排序在不同场景下的时间复杂度。重点介绍了如何优雅地处理Python中的深拷贝问题,以及Golang中的切片复制技巧。
摘要由CSDN通过智能技术生成


题目

leetCode链接:https://leetcode.cn/problems/height-checker/submissions/

1051 . 高度检查器

学校打算为全体学生拍一张年度纪念照。根据要求,学生需要按照 非递减 的高度顺序排成一行。

排序后的高度情况用整数数组 expected 表示,其中 expected[i] 是预计排在这一行中第 i 位的学生的高度(下标从 0 开始)。

给你一个整数数组 heights ,表示 当前学生站位 的高度情况。heights[i] 是这一行中第 i 位学生的高度(下标从 0 开始)。

返回满足 heights[i] != expected[i] 的 下标数量 。

示例:

输入:heights = [1,1,4,2,1,3]
输出:3 
解释:
高度:[1,1,4,2,1,3]
预期:[1,1,1,2,3,4]
下标 2 、4 、5 处的学生高度不匹配。

示例 2:

输入:heights = [5,1,2,3,4]
输出:5
解释:
高度:[5,1,2,3,4]
预期:[1,2,3,4,5]
所有下标的对应学生高度都不匹配。

示例 3:

输入:heights = [1,2,3,4,5]
输出:0
解释:
高度:[1,2,3,4,5]
预期:[1,2,3,4,5]
所有下标的对应学生高度都匹配。

提示:

  • 1 <= heights.length <= 100
  • 1 <= heights[i] <= 100

思路

自然是直接排序然后筛选出不同的值啦。。


解题

python实现

class Solution:
    def heightChecker(self, heights: List[int]) -> int:
        return sum([1 for k,v in enumerate(sorted(heights)) if heights[k]!=v])

golang实现

func heightChecker(heights []int) int {
    origin := make([]int,len(heights))
    copy(origin,heights)
    sort.Ints(heights)
    var result int
    for k,v := range heights {
        if origin[k]!=v{
            result++
        }
    }
    return result
}

复杂度

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn),排序需要时间为 O ( n l o g n ) O(nlogn) O(nlogn),求和需要时间为 O ( n ) O(n) O(n),总复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

空间复杂度 O ( n ) O(n) O(n),排序后数组占用的空间。


总结

看了答案,python还有一种看起来更优雅的写法:

class Solution:
    def heightChecker(self, heights: List[int]) -> int:
        return sum([1 for x,y in zip(sorted(heights), heights) if x!=y])

额外提一嘴关于golang深拷贝的问题。对于golang来说,一个切片本质上是一个列表的地址引用。直接赋值给另一个切片会指向同一内存地址(如果是列表赋值则没有这个问题,列表赋值为值传递):

a := []int{1,2,3,4}
b := a
b[1]=4
fmt.Println(a,b)
// [1,4,3,4] [1,4,3,4]

c := [5]int{1,2,3,4,5}
d := c
d[1]=99
fmt.Println(c,d)
// [1,2,3,4,5] [1,99,3,4,5]

要解决这个问题,就需要使用深拷贝。golang提供了copy函数进行切片深拷贝,但是必须在使用前先申请空间。

heights := []int{1,5,3,4}
var origin []int

// 未申请空间,结果为空
copy(origin,heights)
fmt.Println(origin,heights)
// [] [1,5,3,4]

// 先申请空间
origin = make([]int,len(heights))
copy(origin,heights)
sort.Ints(heights)
fmt.Println(origin,heights)
// [1,5,3,4] [1,3,4,5]

然后就是关于golang的排序,先挖个坑。。。反正网上很多教程了用的时候cv就完事了。。。(逃

最后,答案提供了另一个有趣的解题思路。注意到本题中学生的高度小于等于 100,因此可以使用计数排序,把复杂度变为 O ( n + C ) O(n+C) O(n+C)(c为100或输入中最大值)。n较大时具有明显的优势。

在进行计数排序时,我们可以直接使用一个长度为 101的数组,也可以先对数组heights 进行一次遍历,找出最大值 m,从而使用一个长度为 m+1的数组。

当计数排序完成后,我们可以再使用一个长度为 n 的数组,显式地存储排序后的结果。为了节省空间,我们也直接在计数排序的数组上进行遍历

python:


class Solution:
    def heightChecker(self, heights: List[int]) -> int:
        m = max(heights)
        cnt = [0] * (m + 1)

        for h in heights:
            cnt[h] += 1
        
        idx = ans = 0
        for i in range(1, m + 1):
            for j in range(cnt[i]):
                if heights[idx] != i:
                    ans += 1
                idx += 1
        
        return ans

golang:


func heightChecker(heights []int) (ans int) {
    cnt := [101]int{}
    for _, v := range heights {
        cnt[v]++
    }

    idx := 0
    for i, c := range cnt {
        for ; c > 0; c-- {
            if heights[idx] != i {
                ans++
            }
            idx++
        }
    }
    return
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值