输入: [0, 1, 0, 3, 12]
输出: [1, 3, 12, 0, 0]
方法一(直接求非零元素的最终位置):
- 用一个变量zero_num记录到目前为止遇到0的个数,当元素为0时就将其加一,然后跳过继续遍历下一个数;
- 如果当前的数字不是0,根据zero_num我们可以知道它的最终位置。比如输入数组中,1之前出现过一个0,把这个0去除,等同于1要往前移一位;又如12之前出现过两个0,把这两个0去除,等同于12最终要往前移两位。所以每个非零数字当前下标减去zero_num就是它最终位置的下标,代表它应该往前跳zero_num步;
- 数组全部遍历完后,还剩最后一步:将统计的zero_num个0放到最后。
####### 原始版
l = len(nums)
zero_num = 0 # 记录到目前为止遇到几个0了
for i, num in enumerate(nums):
if num == 0:
zero_num += 1
continue
nums[i-zero_num] = num
# 最后补0
for j in range(l-zero_num, l):
nums[j] = 0
####### 简化版
nums.sort(key=lambda x: x == 0) # True在False之前
方法二(双指针分别记录已排序和未排序的位置):
- 左指针指向已排好序的最后一个数字(最终位置已经确定了,并且其左侧的都是非零数),右指针指向还没排序的第一个数字;
- 如果右指针指的数字为0,则继续往后遍历;如果不为0,那就要让左指针向后一位,并将此时的左右交换,然后右指针继续往后;
- 这种方法利用了左指针和右指针定义对应的性质:
左指针左边的数都是已经排好的非零数,每次右指针找到新的非零数时,左指针会往后一位,如果此时左和右之间有间隔,那间隔的这些数字一定都是0,比如left =0, right = 3时,数组变成了[1, 0 ,0, 3, 12],我们发现右指针所指的3不为0,就会让左指针向后一位,指向1后面的0,然后让0和3互换,这样就会把0不断往后换,但是显然这中间有许多冗余操作,每次都要移动不同的0.
l = len(nums)
left, right = -1, 0
while right<l:
if nums[right]!=0:
left += 1
temp = nums[left]
nums[left] = nums[right]
nums[right] = temp
right += 1