zoukankan      html  css  js  c++  java
  • 算法与数据结构(一) --- 数组

    
    import os
    import torch
    import numpy as np
    import pandas as pd
    import math 
    import random
    from collections import OrderedDict, deque
    from copy import deepcopy
    
    

    案例1: 二分查找

    
    def half_find(li, aim, start=0):
        l = 0
        r = len(li)
        m = int(r/2)
    
        if aim < li[m]:
            # 此时是左边递增,最小值位于右边
            return half_find(li[m+1:r], aim, start=m)
        elif aim > li[m]:
            # 最小值位于mid左面,包含mid
            return half_find(li[l:m+1], aim, start=start)
        else:
            return m, li[m]
    
    if __name__ == '__main__':
        a  =  [12, 51, 81, 94, 111, 165, 198]
        print( half_find(a, 94) )
    

    案例2: 零和数组

    【描述】 元素和最接近0的子数组
    【思路】 记1—n元素和为s(n), 那么有两种情形, S(n)和S(m)-S(n)。其中第二种可以进行排序,取相邻两项做差。排序复杂度nlog(n).

    
    def get_mini_sublist(li):
        part1_index = {}
        part2_index = {}
        
        # 第一部分,前n项求和
        temp = 0
        for i in range(1, len(li)):
            part1_index[(0, i)] = sum(li[:i])
        part1_index = OrderedDict(sorted(part1_index.items(), key=lambda x:x[1] ))
        
        # 第二部分,排序,做差
        t1, t2 = deepcopy(part1_index), deepcopy(part1_index)
        t1.popitem(last=True),
        t2.popitem(last=False)
        
        for i,j in zip(t1.items(), t2.items()):
            part2_index[(i[0][1], j[0][1])] = j[1]-i[1]
        
        # 融合,然后取值最小值    
        part2_index.update(part1_index)         
        key_min = min(part2_index, key=lambda x:abs(part2_index[x]))
        return key_min, part2_index[key_min]
    
    if __name__ == '__main__':
        a = [-1, 32, -21, 22, 12, 11, -2, -12]
        print(get_mini_sublist(a))
    

    3. 旋转数组最小值

    【描述】旋转数组,如[ -2, 3, 5, 6, 9, -10, -5], 特点是把拍好序的数组左边一部分移动到了右边。
    【思路】二分查找

    
    def find_min(li, posotion=0):
        l = 0
        r = len(li)
        m = int(r/2)
    
        if li[l] < li[m]:
            # 此时是左边递增,最小值位于右边
            return find_min(li[m+1:r], posotion=m)
        elif li[l] > li[m]:
            # 最小值位于mid左面,包含mid
            return find_min(li[l:m], posotion=posotion)
        else:
            return li[m], m
    
    if __name__ == '__main__':
        li = [ -2, 3, 5, 6, 9, -10, -5]
        print(find_min(li))
    

    4. 调整数组顺序使奇数位于偶数前面

    【描述】输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
    【思路】创建双向队列,遍历数组,奇数前插入,偶数后插入。

    
    # 双向队列实现
    def reOrderArray1( array):
            # write code here
            odd = deque()
            l = len(array)
            for i in range(l):
                if array[l-i-1] % 2 != 0:
                    odd.appendleft(array[-i-1])
                if array[i] % 2 == 0:
                    odd.append(array[i])
            return list(odd)
    
    # 不开辟新空间
    def reOrderArray2(li):
        temp = 0 # 找出pop的偶数位数, 相应索引左移
        for i in range(len(li)):
            index = i - temp
            if li[index] % 2 == 0:
                li.append(li.pop(index))
                temp += 1
        return li
                
    if __name__ == '__main__':
        li = [ -2, 3, 5, 6, 9, -10, -5]
        print( reOrderArray1(li) )
        print( reOrderArray2(li) )
    
    

    5. 快速找出数组中出现次数超过一半的数字

    【思路】遍历数组,同时存储两个数,{数字值, 数组出现次数}, 出现相同数则次数+1, 不用-1, 若次数为0,则更换数字值。
    考虑到次数超过一般, 那么相同次数应该为正, 保存的数字值应该是最多出现次数

    
    def more_than_half_numb(li):
        num, time, temp = 0, 0, 0
        for i in li:
            if not time:
                temp = num = i
            else:
                if i == temp:
                    time += 1
                else:
                    time -= 1
                
                time +=1
                
                if time <= 0:
                    num = i
        return num
    
    if __name__ == '__main__':
        li = [1,2,3,2,2,2,5,4,2]
        print(more_than_half_numb(li))
            
    

    6. 最大和连续子数组

    【思路】: 动态规划, 每次都比较 当前值 与 累加当前值

    
    def find_max_sub_array(li):
        store = {}
        temp = li[0]
        start, end, sum = 0, 0, temp
    
        for i in range(1, len(li)):
            current = temp + li[i]
            if current >= temp:
                end += 1
                sum += current
            else:
                store[sum] = (start, end)
                start, end = i, i
                sum = li[i]
        result = max(store)
        return result, store[result]
    
    
    if __name__ == '__main__':
        li = [1, 2, 4, 5, -100, 1, -1]
        print(find_max_sub_array(li))
    

    7. 切绳子(可切可不切)

    【思路】: 动态规划, 逐步计算
    【贪心算法】: n>=5 时有 3(n-3)>=2(n-2),优先多3, 最后处理剩余的4, 5

    
    # 动态规划
    def cut(length):
        product = {}
        product[1] = 1
        product[2] = 2 # 必需
        product[3] = 3
    
        for i in range(4, length+1):
            result = max([product[i-j] * product[j] for j in range(1, i)]) #如果必须切, 此处(2, n)
            product[i] = result
        return product
    
    if __name__ == '__main__':
        print(cut(20))
    
    

    8. 把数组排成最小的数

    【思路】: 应用字符串比较最为方便

    def join2max(li):
        result = sorted(map(lambda x: str(x), a), reverse=True)
        return int(''.join(result))
    
    if __name__ == '__main__':
        a = np.random.randint(1000,size=10)
        print(join2max(a))
    

    9. 数组中的逆序对

    【题目】在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。
    【思路】归并排序

    class MergeSort:
        def __init__(self):
            self.num = 0
        def _merge(self, a, b):
            result = []
            while a and b:
                if a[0]<=b[0]:
                    result.append( a.pop(0) )
                else:
                    result.append( b.pop(0) )
                    self.num += len(a)
            result.extend(a if a else b)
            return result
        
        def __call__(self, li):
            length = len(li)
            if length == 1:
                return li
            else: 
                mid = int(len(li) / 2)
                left = self.__call__(li[:mid])
                right = self.__call__(li[mid:])    
                return self._merge(left, right)
            
    if __name__ == '__main__':
        a = list(np.random.randint(1, 100, 10))
        sort = MergeSort()
        print(sort([1, 3, 5, 2, 7]))
        print('逆序对数量为: {}'.format(sort.num))
    
  • 相关阅读:
    Spring SpringFactoriesLoader
    java8函数式接口 Supplier
    Spring DefaultResourceLoader
    Spring ProtocolResolver接口
    StringBuilder&StringBuffer
    java自动自动拆装箱
    Spring ClassPathResource
    windows10风格 springboot vue.js html 跨域 前后分离 activiti 整合项目框架源码
    SQL语句及数据库优化
    tomcat添加https服务
  • 原文地址:https://www.cnblogs.com/geoffreyone/p/11506019.html
Copyright © 2011-2022 走看看