python数据结构与算法学习笔记(一)

源于github上的一个10k+star项目

传送门

本系列记录思路,以作备忘

array 数组

  • delete_nth

删除第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
  • flatten

数组降维

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)可以设置最大递归次数
  • garage

停车场问题: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添加的是地址、引用,当这个引用内容被改变时,前面添加的相同地址的内容也随之改变
  • josephus_problem

约瑟夫环问题,一组数字围成圆,按某一步长剔除元素,剔除后下一元素按步长继续

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
  • max_ones_index
一个只有1和0的一元数组,用1替换0得到一个连续的1的序列,每次只能替换一个,求能最长序列的替换index,如果数组没0返回-1

例:[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

  • limit

给定一个不含重复元素的数组、最小值、最大值,返回相对位置不变的只包含最小值~最大值的数组,时间复杂度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
#思路:遍历的同时加限制条件
  • longest_non_repeat

给定一个字符串,返回不含重复元素的最大子字符串长度。

例:'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)
  • merge_intervals 合并区间

 -。-没看懂题目。跳过

  • missing_ranges 缺失范围

对于给定数组,找到给定下限值,上限值之间数组范围之外的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 
#思路:左边界值在遍历数组的同时随着数组元素值向右边界靠近
  • plus_one +1运算
用一个数组代表一个非负整数,实现+1功能(有进位功能)

例:[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:编辑器有点不会用,可能有排版问题,望见谅

猜你喜欢

转载自blog.csdn.net/jizhonghua2768/article/details/80783923