题目
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
}