源于github上的一个10k+star项目
传送门
本系列记录思路,以作备忘
删除第n次出现的元素
import collections
#input = [1,2,3,1,2,1,2,3]
#target = [1,2,3,1,2,3]
# 因count实现为遍历对象,构建dict返回,故时间复杂度为O(n^2)
def delete_nth_naive(array,n):
ans = []
for num in array:
if ans.count(num) < n:
ans.append(num)
return ans
#使用collections.defaultdict实际上是相当于自己实现了count方法构建了dict,时间复杂度O(1), 总时间复杂度为O(n)
def delete_nth(array, n):
result = []
counts = collections.defaultdict(int)
for i in array:
if counts[i] < n:
result.append(i)
counts[i] += 1
return result
数组降维
from collections import Iterable
# 递归思想实现数组降维,返回list
def flatten(input_arr, output_arr=None):
if output_arr is None:
output_arr = []
for ele in input_arr:
if isinstance(ele, Iterable):
flatten(ele, output_arr)
else:
output_att.append(ele)
return output_arr
# 递归思想实现数组降维,返回generator, 好处惰性加载,节约内存
def flatten_iter(iterable):
for element in iterable:
if isinstance(element, Iterable):
yield from flatten_iter(element)
else:
yield element
#ps.python默认最大递归次数为1000,所以数组维数过大时会抛出 maximum recursion depth exceeded while calling a Python object 错误
#使用sys模块的sys.setrecursionlimit(1500)可以设置最大递归次数
停车场问题:0代表空位,每步只可移动一辆车到空位,最少步数达到目标要求
# 初始:[1,2,3,0,4], 目标:[0,3,2,1,4]
#[1,2,3,0,4]→[0,2,3,1,4]→[2,0,3,1,4]→[2,3,0,1,4]→[0,3,2,1,4]
def garage(initial, final):
initial = initial[::]
steps = 0
seq = []
while initial != final:
zero = initial.index(0):
if zero != final.index(0):
car_to_move = final[zero]
pos = initial.index(car_to_move)
initial[zero],initial[pos] = initial[pos],initial[zero]
else:
for i in range(len(initial)):
if initial[i] != final[i]:
initial[zero],initial[i] = initial[i],initial[zero]
break
seq.append(initial[::])
steps += 1
return steps, seq
# 思路:利用0来定位,获取initial里0的index,再获取final对应index值n,在initial里n值和0值位置互换,循环,直到initial==final
# ps.seq.append(initial[::])里initial[::]的作用是复制,直接用initial会用最后一次的值覆盖前面的,原因是append添加的是地址、引用,当这个引用内容被改变时,前面添加的相同地址的内容也随之改变
约瑟夫环问题,一组数字围成圆,按某一步长剔除元素,剔除后下一元素按步长继续
def josephus(int_list, skip):
skip = skip - 1 #list starts with 0 index
idx = 0
len_list = len(int_list)
whilel len_list > 0:
idx = (skip+idx) % len_list #hash index to every 3rd
yield int_list.pop(idx)
len_list -= 1
#思路:pop出一个元素后,后面元素的index会依次-1,下一个需pop的元素index即当前index+2
例:[1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1]→[1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1] 得到最长的1的序列,返回0的index 3
def max_ones_index(arr):
n = len(arr)
max_count = 0
max_index = 0
prev_zero = -1
prev_prev_zero = -1
for curr in range(n):
if arr[curr] == 0:
if curr - prev_prev_zero > max_count:
max_count = curr - prev_prev_zero
max_index = prev_zero
prev_prev_zero = prev_zero
prev_zero = curr
if n - prev_prev_zero > max_count:
max_index = prev_zero
return max_index
#思路:替换后连续序列的长度取决于它两边0点的index,进行遍历时保存上一个0点index和上上个0点的index,curr - prev_prev_zero就是prev_zero替换后序列能达到的最大长度+1
给定一个不含重复元素的数组、最小值、最大值,返回相对位置不变的只包含最小值~最大值的数组,时间复杂度O(n)
例:limit([1,2,3,4,5],None,3) = [1,2,3]
def limit(arr, min_lim=None, max_lim=None):
result = []
if min_lim == None:
for i in arr:
if i <= max_lim:
result.append(i)
elif max_lim == None:
for i in arr:
if i >= min_lim:
result.append(i)
else:
for i in arr:
if i >= min_lim and i <= max_lim:
result.append(i)
return result
#思路:遍历的同时加限制条件
给定一个字符串,返回不含重复元素的最大子字符串长度。
例:'pwwkew',最大子字符串 'wke',长度3
def longest_non_repeat_v1(string):
if string is None:
return 0
temp = []
max_len = 0
for i in string:
if i in temp:
temp = []
temp.append(i)
max_len = max(max_len,len(temp))
return max_len
#思路:遍历的同时做判断,出现重复元素就清空,时间复杂度O(n^2)
def longest_non_repeat_v2(string):
if string is None:
return 0
start, max_len = 0, 0
used_char = {}
for index, char in enumerate(string):
if char in used_char and start <= used_char[char]:
start = used_char[char]
else:
max_len = max(max_len, index - start)
used_char[char] = index
return max_len
#思路:start记录的是出现重复元素后该元素上次出现的index,当前index - start即为出现重复元素前最大值,由于引入字典,时间复杂度O(n) * O(1) = O(n)
-。-没看懂题目。跳过
对于给定数组,找到给定下限值,上限值之间数组范围之外的range
例:[3,5],lo=1,hi=10 → answer : [(1,2),(4,4),(6,10)]
def missing_ranges(arr, lo, hi):
res = []
start = lo
for n in arr:
if n == start:
start += 1
elif n > start:
res.append((start, n-1))
start = n + 1
if start <= hi:
res.append((start, hi))
return res
#思路:左边界值在遍历数组的同时随着数组元素值向右边界靠近
例:[1,2,3,9,9] → puls_one → [1,2,4,0,0]
def plus_one_v1(digits):
digits[-1] = digits[-1] + 1
res = []
ten = 0
i = len(digits) - 1
while i >= 0 or ten == 1:
summ = 0
if i >= 0:
summ += digits[i]
if ten:
summ += 1
res.append(summ % 10)
ten = summ // 10
i -= 1
return res[::-1]
def plus_one_v2(digits):
n = len(digits)
for i in range(n-1,-1,-1):
if digits[i] < 9:
digits += 1
return digits
digits[i] = 0
digits.insert(0, 1)
return digits
def plus_one_v3(num_arr):
for idx, digit in reversed(list(enumerate(num_arr))):
num_arr[idx] = (num_arr[idx] + 1) % 10
if num_arr[idx]:
return num_arr
return [1]+num_arr
#思路:[...万,千,百,十,个],这样看数组,逐位进行判断
未完待续......
ps:编辑器有点不会用,可能有排版问题,望见谅