• 01-时间复杂度、对数器(python)、冒泡、选择、递归实质、归并、小和问题、逆序对、mid


     1、时间复杂度 

    常数时间的操作:一个操作如果和数据量没有关系,每次都是
    固定时间内完成的操作,叫做常数操作。


    时间复杂度为一个算法流程中,常数操作数量的指标。常用O
    (读作big O)来表示。

    具体来说,在常数操作数量的表达式中,
    只要高阶项,不要低阶项,也不要高阶项的系数,剩下的部分
    如果记为f(N),那么时间复杂度为O(f(N))。


    评价一个算法流程的好坏,先看时间复杂度的指标,然后再分
    析不同数据样本下的实际运行时间,也就是常数项时间。

    例子一:理解时间复杂度

    一个简单的理解时间复杂度的例子
    一个有序数组A,另一个无序数组B,请打印B中的所有不在A中的数,A数
    组长度为N,B数组长度为M。
    算法流程1:对于数组B中的每一个数,都在A中通过遍历的方式找一下;
    算法流程2:对于数组B中的每一个数,都在A中通过二分的方式找一下;
    算法流程3:先把数组B排序,然后用类似外排的方式打印所有不在A中出现
    的数;
    三个流程,三种时间复杂度的表达...
    如何分析好坏?

    2、冒泡排序

    冒泡排序细节的讲解与复杂度分析
    时间复杂度O(N^2),额外空间复杂度O(1)

     

     java版本

    package basic_class_01;
    
    import java.util.Arrays;
    
    public class Code_00_BubbleSort {
    
        public static void bubbleSort(int[] arr) {
            if (arr == null || arr.length < 2) {
                return;
            }
            for (int e = arr.length - 1; e > 0; e--) {
                for (int i = 0; i < e; i++) {
                    if (arr[i] > arr[i + 1]) {
                        swap(arr, i, i + 1);
                    }
                }
            }
        }
    
        public static void swap(int[] arr, int i, int j) {
            arr[i] = arr[i] ^ arr[j];
            arr[j] = arr[i] ^ arr[j];
            arr[i] = arr[i] ^ arr[j];
        }
    
    }

     python版本

    # 冒泡排序
    # 时间复杂度O(N^2)
    # 空间复杂度O(1)
    
    def bubble_sort(li):
        if li is None and len(li) < 2:
            return
        for end in range(len(li) - 1, -1, -1):
            for i in range(end):
                if li[i] > li[i + 1]:
                    swap(li, i, i + 1)
        return li
    
    # 优化版本
    def bubble_sort1(li):
        if li is None and len(li) < 2:
            return
        for end in range(len(li) - 1, -1, -1):
            exchange = False   # 设置哨兵
            for i in range(end):
                if li[i] > li[i + 1]:
                    swap(li, i, i + 1)
                    exchange = True
            if not exchange:
                return li
        return li
    
    def swap(data, i, j):
        temp = data[i]
        data[i] = data[j]
        data[j] = temp
    
    # for test
    ret = bubble_sort([9, 2, 7, 8, 3, 2, 1])
    print(ret)

    3、选择排序

    选择排序的细节讲解与复杂度分析
    时间复杂度O(N^2),额外空间复杂度O(1)

     java版本

    package basic_class_01;
    
    import java.util.Arrays;
    
    public class Code_02_SelectionSort {
    
        public static void selectionSort(int[] arr) {
            if (arr == null || arr.length < 2) {
                return;
            }
            for (int i = 0; i < arr.length - 1; i++) {
                int minIndex = i;
                for (int j = i + 1; j < arr.length; j++) {
                    minIndex = arr[j] < arr[minIndex] ? j : minIndex;
                }
                swap(arr, i, minIndex);
            }
        }
    
        public static void swap(int[] arr, int i, int j) {
            int tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
    
    
    }

    python版本

    # 选择排序
    # 时间复杂度O(N^2)
    # 空间复杂度O(1)
    
    def selection_sort(li):
        if li is None and len(li) < 2:
            return
        for i in range(len(li) - 1):   # 当前n-1个确定好了,最后一个就确定ok
            min_index = i
            for j in range(i + 1, len(li)):
                if li[j] < li[min_index]:
                    min_index = j
                swap(li, i, min_index)
        return li
    
    def swap(data, i, j):
        data[i] = data[i] ^ data[j]
        data[j] = data[i] ^ data[j]
        data[i] = data[i] ^ data[j]
    
    # for test
    ret = selection_sort([9, 2, 7, 8, 3, 2, 1])
    print(ret)

    4、插入排序 

    插入排序的细节讲解与复杂度分析
    时间复杂度O(N^2),额外空间复杂度O(1)

     java版本

        public static void insertionSort(int[] arr) {
            if (arr == null || arr.length < 2) {
                return;
            }
            for (int i = 1; i < arr.length; i++) {
                for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
                    swap(arr, j, j + 1);
                }
            }
        }
    
        public static void swap(int[] arr, int i, int j) {
            arr[i] = arr[i] ^ arr[j];
            arr[j] = arr[i] ^ arr[j];
            arr[i] = arr[i] ^ arr[j];
        }

     python版本

    # 插入排序
    # 时间复杂度O(N^2)
    # 空间复杂度O(1)
    
    def selection_sort(li):
        if li is None and len(li) < 2:
            return
        for i in range(1, len(li)):
            temp = li[i]
            j = i - 1
            while j >= 0 and temp < li[j]:
                li[j + 1] = li[j]   # 元素往后推一个位置
                j -= 1
            li[j + 1] = temp   # 最小元素放在第一个位置
        return li
    
    # for test
    ret = selection_sort([9, 2, 7, 8, 3, 2, 1])
    print(ret)

    5、对数器

    1、用途:验证算法是否正确的一种方式

    2、使用
      0,有一个你想要测的方法a,
      1,实现一个绝对正确但是复杂度不好的方法b,
      2,实现一个随机样本产生器
      3,实现比对的方法
      4,把方法a和方法b比对很多次来验证方法a是否正确。
      5,如果有一个样本使得比对出错,打印样本分析是哪个方法出错
      6,当样本数量很多时比对测试依然正确,可以确定方法a已经正确。

     3、实现

    1.随机数组发生器
    2.准备一个绝对正确的方法
    3.大样本测试  500 000

    java版本

    package basic_class_01;
    
    import java.util.Arrays;
    
    public class Code_00_BubbleSort {
    
        // 需要验证的算法??  
        public static void bubbleSort(int[] arr) {
            if (arr == null || arr.length < 2) {
                return;
            }
            for (int e = arr.length - 1; e > 0; e--) {
                for (int i = 0; i < e; i++) {
                    if (arr[i] > arr[i + 1]) {
                        swap(arr, i, i + 1);
                    }
                }
            }
        }
    
        public static void swap(int[] arr, int i, int j) {
            arr[i] = arr[i] ^ arr[j];
            arr[j] = arr[i] ^ arr[j];
            arr[i] = arr[i] ^ arr[j];
        }
    
    
        // 1.随机数组发生器
        // for test
        public static int[] generateRandomArray(int maxSize, int maxValue) {
            // Math.random() -> double [0,1)
            // (int) ((size+1)*Math.random())  -> [0,size]  整数
            // size = 6, size+1 = 7
            // Math.random() -> [0,1) * 7 -> [0,7) double
            // double -> int[0,6) -> int
            
            // 生成长度随机的数组
            int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
            for (int i = 0; i < arr.length; i++) {
                arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
            }
            return arr;
        }
    
        
        // 2.准备一个绝对正确的方法
        // for test
        public static void comparator(int[] arr) {
            Arrays.sort(arr);
        }
    
        
        // 3.大样本测试  500 000
        // for test
        public static void main(String[] args) {
            int testTime = 500000;
            int maxSize = 100;
            int maxValue = 100;
            boolean succeed = true;
            for (int i = 0; i < testTime; i++) {
                int[] arr1 = generateRandomArray(maxSize, maxValue);
                int[] arr2 = copyArray(arr1);
                bubbleSort(arr1);
                comparator(arr2);
                if (!isEqual(arr1, arr2)) {
                    succeed = false;
                    break;
                }
            }
            System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    
            int[] arr = generateRandomArray(maxSize, maxValue);
            printArray(arr);
            bubbleSort(arr);
            printArray(arr);
        }
    
        //3.1 copy
        // for test
        public static int[] copyArray(int[] arr) {
            if (arr == null) {
                return null;
            }
            int[] res = new int[arr.length];
            for (int i = 0; i < arr.length; i++) {
                res[i] = arr[i];
            }
            return res;
        }
    
        // 3.2 验证isEqual,长度一样,每位的数字一样
        // for test
        public static boolean isEqual(int[] arr1, int[] arr2) {
            if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
                return false;
            }
            if (arr1 == null && arr2 == null) {
                return true;
            }
            if (arr1.length != arr2.length) {
                return false;
            }
            for (int i = 0; i < arr1.length; i++) {
                if (arr1[i] != arr2[i]) {
                    return false;
                }
            }
            return true;
        }
    
        // 3.3 打印结果
        // for test
        public static void printArray(int[] arr) {
            if (arr == null) {
                return;
            }
            for (int i = 0; i < arr.length; i++) {
                System.out.print(arr[i] + " ");
            }
            System.out.println();
        }
    
    
    }

     python版本

    import random
    
    # 我的方法
    def bubble_sort(li):
        if li is None or len(li) < 2:
            return li
        for end in range(len(li) - 1, -1, -1):
            for i in range(end):
                if li[i] > li[i + 1]:
                    swap(li, i, i + 1)
        return li
    
    # 交换两个数字,与
    def swap(data, i, j):
        data[i] = data[i] ^ data[j]
        data[j] = data[i] ^ data[j]
        data[i] = data[i] ^ data[j]
        
        
    '''for test'''
    # 1.随机数组发生器
    def generate_random_array(max_size,max_vaule):
        arr = []
        arr_len = int((max_size+1)*random.random())  # 长度随机,不能大于max_size
        for i in range(arr_len):
            arr.append(int((max_vaule + 1) * random.random()) - int(max_vaule * random.random()))  # value随机
        return arr
    
    # 2.准备一个绝对正确的方法
    def comparator(arr):
        return sorted(arr)
    
    # 3.大样本测试 500 000
    def main():
        test_time = 500
        max_size = 100
        max_value = 100
        succeed = True
        for i in range(test_time):
            arr1 = generate_random_array(max_size,max_value)
            arr2 = copy_array(arr1)
    
            arr1 = bubble_sort(arr1)  # 我的方法
            arr2 = comparator(arr2)   # 系统绝对正确的方法
    
            if not is_equal(arr1,arr2):
                succeed = False
                break
    
        print("Nice") if succeed else print("Fucking fucked")
    
        arr = generate_random_array(max_size,max_value)
        print_array(arr)
        bubble_sort(arr)
        print_array(arr)
    
    # 3.1 copy
    def copy_array(arr):
        if arr is None:
            return None
        res = []
        for i in range(len(arr)):
            res.append(arr[i])
        return res
    
    # 3.2 验证isEqual,长度一样,每位的数字一样
    def is_equal(arr1,arr2):
        if (arr1 is None and arr2 is not None) or (arr1 is not None and arr2 is None):
            return False
        if arr1 is None and arr2 is None:
            return True
        if len(arr1) != len(arr2):
            return False
        for i in range(len(arr1)):
            if arr1[i] != arr2[i]:
                return False
        return True
    
    # 3.3 打印结果
    def print_array(arr):
        if arr is None:
            return
        for i in range(len(arr)):
            print(arr[i],end=' ')
        print('
    ')
    
    
    if __name__ == '__main__':
        main()

     6、递归

    6.1 递归实质

    剖析递归行为和递归行为时间复杂度的估算
    一个递归行为的例子

    def get_max(arr,left,right):
        if left == right:
            return arr[left]
        mid = (left+right)//2
        max_left = get_max(arr,left,mid)
        max_right = get_max(arr,mid+1,right)
        return max(max_left,max_right)
    
    li = [4,3,2,1]
    ret = get_max(li,0,len(li)-1)
    print(ret)   # 4

    还原现场 ,系统栈  

    6.2 递归行为复杂度通式

    master公式的使用

    T(N) = a*T(N/b) + O(N^d)

    1) log(b,a) > d -> 复杂度为O(N^log(b,a))
    2) log(b,a) = d -> 复杂度为O(N^d * logN)
    3) log(b,a) < d -> 复杂度为O(N^d)


    补充阅读:www.gocalf.com/blog/algorithm-complexity-and-master-
    theorem.html

     7、归并排序(递归、分治)

    归并排序的细节讲解与复杂度分析
    时间复杂度O(N*logN),额外空间复杂度O(N)

     java版本

    public static void mergeSort(int[] arr) {
            if (arr == null || arr.length < 2) {
                return;
            }
            mergeSort(arr, 0, arr.length - 1);
        }
    
        public static void mergeSort(int[] arr, int l, int r) {
            if (l == r) {
                return;
            }
            int mid = l + ((r - l) >> 1);
            mergeSort(arr, l, mid);
            mergeSort(arr, mid + 1, r);
            merge(arr, l, mid, r);
        }
    
        public static void merge(int[] arr, int l, int m, int r) {
            int[] help = new int[r - l + 1];
            int i = 0;
            int p1 = l;
            int p2 = m + 1;
            while (p1 <= m && p2 <= r) {
                help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
            }
            while (p1 <= m) {
                help[i++] = arr[p1++];
            }
            while (p2 <= r) {
                help[i++] = arr[p2++];
            }
            for (i = 0; i < help.length; i++) {
                arr[l + i] = help[i];
            }
        }

    python版本

    def mergeSort(arr):
        if arr is None or len(arr) < 2:
            return arr
        merge_sort(arr,0,len(arr)-1)
        return arr
    
    def merge_sort(arr,left,right):
        if left == right:
            return arr
        mid = left + ((right-left)>>1)  # left和right中点的位置 (L+R)//2
        # 分解
        merge_sort(arr,left,mid)     # T(n/2)
        merge_sort(arr,mid+1,right)  # T(n/2)
    
        # 合并
        merge(arr,left,mid,right)   # O(n)
        # T(n)  = 2T(N/2)+ O(N)
    
    def merge(arr,left,mid,right):
        temp = []
        i,j = left,mid+1
        while i<=mid and j <= right:
            if arr[i]<arr[j]:
                temp.append(arr[i])
                i += 1
            else:
                temp.append(arr[j])
                j +=1
    
        # 两个必且有一个越界
        while i<=mid:
            temp.append(arr[i])
            i += 1
        while j<=right:
            temp.append(arr[j])
            j += 1
    
        arr[left:right+1] = temp
    
    
    li = [3,1,2,4]
    ret = mergeSort(li)
    print(ret)

    时间复杂度估算

    为什么归并排序比较快

    其他排序,有很多无效的比较,浪费比较

    8、小和问题

    小和问题
    在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组
    的小和。
    例子:
      [1,3,4,2,5]
      1左边比1小的数,没有;
      3左边比3小的数,1;
      4左边比4小的数,1、3;
      2左边比2小的数,1;
      5左边比5小的数,1、3、4、2;
      所以小和为1+1+3+1+1+3+4+2=16

      4*1 + 2*3 + 1*4 + 1*2

    java版本

        public static int smallSum(int[] arr) {
            if (arr == null || arr.length < 2) {
                return 0;
            }
            return mergeSort(arr, 0, arr.length - 1);
        }
    
        public static int mergeSort(int[] arr, int l, int r) {
            if (l == r) {
                return 0;
            }
            int mid = l + ((r - l) >> 1);
            return mergeSort(arr, l, mid) + mergeSort(arr, mid + 1, r) + merge(arr, l, mid, r);
        }
    
        public static int merge(int[] arr, int l, int m, int r) {
            int[] help = new int[r - l + 1];
            int i = 0;
            int p1 = l;
            int p2 = m + 1;
            int res = 0;
            while (p1 <= m && p2 <= r) {
                res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;
                help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
            }
            while (p1 <= m) {
                help[i++] = arr[p1++];
            }
            while (p2 <= r) {
                help[i++] = arr[p2++];
            }
            for (i = 0; i < help.length; i++) {
                arr[l + i] = help[i];
            }
            return res;
        }

    python版本

    def small_sum(arr):
        if arr is None or len(arr) < 2:
            return arr
        return merge_sort(arr, 0, len(arr) - 1)
    
    
    def merge_sort(arr, l, r):
        if l == r:
            # return arr   要进行res相加操作
            return 0
    
        m = l + ((r - l) >> 1)  # m = (L+R)//2
        return merge_sort(arr, l, m) + merge_sort(arr, m + 1, r) + merge(arr, l, m, r)
    
    def merge(arr, l, m, r):
        temp = []
        i, j = l, m + 1
    
        res = 0  # 每次merge产生的 小和
    
        while i <= m and j <= r:
            res += (r - j + 1) * arr[i] if arr[i] < arr[j] else 0  # 小和
    
            if arr[i] < arr[j]:
                temp.append(arr[i])
                i += 1
            else:
                temp.append(arr[j])
                j += 1
    
        # 两个必且有一个越界
        while i <= m:
            temp.append(arr[i])
            i += 1
        while j <= r:
            temp.append(arr[j])
            j += 1
    
        for i in range(len(temp)):
            arr[l + i] = temp[i]
    
        return res
    
    
    arr = [1,3,4,2,5]
    print(small_sum(arr))
    res += (r - j + 1) * arr[i] if arr[i] < arr[j] else 0  # 小和

       

     左神语录

    有一个思路要给大家贯彻到底的
    所有东西都是技术问题
    你写不出来的原因是因为缺乏练习,
    而不是你这个人笨
    你知道吗,真的是要建立这种信心

    因为我就是那样的阶段趟过来的,
    这其中的辛苦确实都知道

     9、逆序对问题

    在一个数组中,左边的数如果比右边的数大,则折两个数构成一个逆序对,请打印所有逆序
    对。

     10、取mid的几种方法

     

    11、交换两个数的值

      方法1:  
        tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;

    方法2:
            arr[i] = arr[i] ^ arr[j];
            arr[j] = arr[i] ^ arr[j];
            arr[i] = arr[i] ^ arr[j];

    Z、总结

    1、时间复杂度

    big O  代表常数操作

    只要高阶项,不要低阶项,也不要高阶项的系数

    2、冒泡

    时间复杂度O(N^2)

    额外空间复杂度O(1)

    3、选择

    时间复杂度O(N^2)

    额外空间复杂度O(1)

     
    4、插入
    时间复杂度O(N^2)
    额外空间复杂度O(1)
     
    5、对数器
    验证算法是否正确的一种方式
     
    1) 随机数组发生器:长度随机,value随机的数组
    2) 一个绝对正确的方法。
    3) 我要验证的方法
    4) 大样本测试:50000
    5) isEqual :长度一样,每一位数字都相同

    6、递归实质

    还原现场:系统压栈操作

    7、递归的master公式

    T(N) = a*T(N/b) + O(N^d)

    8、归并排序 (重要)

    递归、分治 思想

    时间复杂度O(N*logN)

    额外空间复杂度O(N)

    归并排序为什么比其他的快?

    其他排序,有很多无效的比较,浪费比较

    9、小和问题

    例子:
      [1,3,4,2,5]
      1左边比1小的数,没有;
      3左边比3小的数,1;
      4左边比4小的数,1、3;
      2左边比2小的数,1;
      5左边比5小的数,1、3、4、2;
      所以小和为1+1+3+1+1+3+4+2=16

      4*1 + 2*3 + 1*4 + 1*2

    归并合并的时候,每次炸出 小和

    炸出 (right-j+1)* arr[i]

    炸出 4个 1 的小和

    炸出 2个 3 的小和

    炸出 1个 4 的小和

    炸出 1个 2 的小和

    10、逆序对问题

    在一个数组中,左边的数如果比右边的数大,

    则折两个数构成一个逆序对,请打印所有逆序对

    也用归并排序 

    11、取mid的几种方法

     

    12、交换两个数的值

      方法1:  
        tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;

    方法2:
            arr[i] = arr[i] ^ arr[j];
            arr[j] = arr[i] ^ arr[j];
            arr[i] = arr[i] ^ arr[j];

    左神语录

    有一个思路要给大家贯彻到底的
    所有东西都是技术问题
    你写不出来的原因是因为缺乏练习,
    而不是你这个人笨
    你知道吗,真的是要建立这种信心

    因为我就是那样的阶段趟过来的,
    这其中的辛苦确实都知道

    准备模板,必要裸奔取考试

    1、对数器

    2、堆,排序

  • 相关阅读:
    SpringMVC之五:自定义DispatcherServlet配置及配置额外的 servlets 和 filters
    DTP模型之一:(XA协议之三)MySQL数据库分布式事务XA优缺点与改进方案
    Spring Bean基本管理--bean注入方式汇总
    类装载器ClassLoader
    spring中的BeanFactory与ApplicationContext的作用和区别?
    Spring IoC,IoC原理
    mybatis实战教程(mybatis in action)之九:mybatis 代码生成工具的使用
    session.write类型引发的思考---Mina Session.write流程探索.doc--zhengli
    MyBatis的association示例——MyBatis学习笔记之三
    MyBatis一对多双向关联——MyBatis学习笔记之七
  • 原文地址:https://www.cnblogs.com/venicid/p/9853806.html
Copyright © 2020-2023  润新知