Python是一种简易的脚本语言,在我平时的各类作业任务中Python脚本程序经常能给予很大的帮助。比如,生成大量测试数据、编写一个支持小规模指令集的编译工具、画图等等工作都可以由Python高效完成。大部分时候只需要程序功能正确即可大幅提升工作效率。不过前段时间,我在完成一些作业和小项目时,发现使用Python编写的程序中算法性能不好有时还是会严重影响完成作业项目的效率,其中有一个项目由于程序运行过慢导致实验分析的效率被严重拖累,因此我想抽时间学习Python算法的高性能实现。我想试试LeetCode练习,从相对简单的题目入手,采用Python实现算法要求
Python 练习 数组: LeetCode 26 删除有序数组中的重复项
给你一个非严格递增排列的数组nums
,请你原地删除重复出现的元素,使每个元素只出现一次 ,返回删除后数组的新长度。元素的相对顺序应该保持一致 。然后返回nums
中唯一元素的个数。
考虑nums
的唯一元素的数量为k
,你需要做以下事情确保你的题解可以被通过:
- 更改数组
nums
,使nums
的前k
个元素包含唯一元素,并按照它们最初在nums
中出现的顺序排列。nums
的其余元素与nums
的大小不重要。 - 返回
k
。
判题标准:
系统会用下面的代码来测试你的题解:
int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案
int k = removeDuplicates(nums); // 调用
assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
assert nums[i] == expectedNums[i];
}
如果所有断言都通过,那么您的题解将被通过。
题解一
暴力求解
我首先想到的是暴力求解,先跑出结果再优化性能。思路是遍历数组(Python列表),如果有重复元素就移到数组后面,用一个指针控制数组的遍历进度
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) < 2:
return len(nums)
valid_length = len(nums)
pointer = 0
while (pointer < valid_length-1):
if nums[pointer] == nums[pointer+1]:
if pointer < valid_length - 2:
nums[:] = nums[:pointer+1] + nums[pointer+2:] + nums[pointer+1:pointer+1]
valid_length -= 1
else:
pointer += 1
return valid_length
这里需要注意,如果想在Python函数内修改函数的列表形参,而且返回值不包含该列表,则在重新给列表赋值时要使用列表切片nums[:]
的方式,直接对nums
赋值无法完成列表内容的修改
nums[:] = nums[:pointer+1] + nums[pointer+2:] + nums[pointer+1:pointer+1]
我试了几个例子在本地能运行通过,但是在LeetCode上测到第三个例子就超时了。需要优化时间复杂度
题解二:
暴力求解 优化
题解二的思路和题解一类似。考虑到题目要求说数组长度与多余元素值不重要,因此可以直接删除重复值
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) < 2:
return len(nums)
valid_length = len(nums)
pointer = 0
while (pointer < valid_length-1):
if nums[pointer] == nums[pointer+1]:
del nums[pointer+1]
valid_length -= 1
else:
pointer += 1
return valid_length
题解二可以跑通LeetCode的测试案例,空间复杂度较低,但是时间复杂度需要进一步优化
题解三:
set()去重
最后,我想到Python的内置set()
方法可以将列表元素去重。得到的集合是乱序的,不过由于题目给定数组已按升序排序,因此可以直接采用sorted()
方法恢复列表元素顺序
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums[:] = sorted( list(set(nums)) )
valid_length = len(nums)
return valid_length
如果题目给定了其他排序方式,可以用sorted()
方法的key
参数还原列表元素顺序
newSet = set(listRandom)
noRepeat = list(newSet)
noRepeat.sort(key=listRandom.index)
尽管题解三的空间复杂度较题解二高了一些,但是算法的时间复杂度实现了巨大优化
小结:
内置方法的优化程度非常高,在写Python脚本时应多采用Python的内置方法(set()
、sorted()
等等)和高度优化的运算库(numpy
等),这样程序的时间复杂度将得到巨大提升