基础班:第一节

版权声明:本文为博主DarkAngel1228原创文章,未经博主允许不得转载。 https://blog.csdn.net/DarkAngel1228/article/details/82941238

一. 算法的衡量标准

1.1 时间复杂度

在计算机科学中,算法的时间复杂度是一个函数,它定性描述了该算法的运行时间。
这是一个关于代表算法输入值的字符串的长度的函数。
时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。

1.2 空间复杂度

空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度,记做S(n)=O(f(n))。
比如直接插入排序的时间复杂度是O(n^2),空间复杂度是O(1) 。
而一般的递归算法就要有O(n)的空间复杂度了,因为每次递归都要存储返回信息

1.3 举例理解时间复杂度

一个有序数组A,另一个无序数组B,请打印B中的所有不在A中的数。A数组长度为N,B数组长度为M。
三种流程,三种时间复杂度的表达式

算法流程1:对于数组B中的每一个数,都在A中通过遍历的方式找一下。

O(M*N)

算法流程2:对于数组B中的每一个数,都在A中通过二分的方法找一下。

O(M*log2N)

算法流程3:先把数组B排序,然后用类似外排的方式打印所有不在A中出现的数。

O(M*log2M)+O(N+M)

分析:排除算法1。
如果A数组个数比较少,相对来说数组B个数比较多,算法2较好。
如果A数组个数比较多,相对来说数组B个数比较少,算法3较好。

二. 对数器

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

三. 冒泡排序

时间复杂度O(N2),额外空间复杂度O(1)

// 冒泡排序 先减后加是冒泡、冒泡加中有if
protected function bubbleSort(&$data)
    {
        $dataNum = count($data);

        if ($dataNum < 2) {
            return $data;
        }

        for ($j=$dataNum-1; $j > 0 ; $j--) { 
            for ($i=0; $i < $j; $i++) { 
                if ($data[$i] > $data[$i+1]) {
                    $this->swap($data, $i, $i+1);
                }
            }
        }
    }

四. 选择排序

时间复杂度O(N2),额外空间复杂度O(1)

// 选择排序 选择排序有加加、三元变量和if
    protected function selectionSort(Array $data)
    {
        $dataNum = count($data);

        for ($j=0; $j < $dataNum - 1; $j++) { 
            $minIndex = $j;

            for ($i=$j+1; $i < $dataNum; $i++) { 
                $minIndex = $data[$i] < $data[$minIndex] ? $i : $minIndex ;
            }

            if ($minIndex != $j) {
                $tmp = $data[$minIndex];
                $data[$minIndex] = $data[$j];
                $data[$j] = $tmp;
            }
        }

        return $data;
    }

五. 插入排序

时间复杂度O(N2),额外空间复杂度O(1)

 	// 插入排序 先加后减是插入、插入减中有&
    protected function insertionSort(&$data)
    {
        $dataNum = count($data);

        for ($j=1; $j < $dataNum; $j++) { 

            for ($i=$j ; $i > 0 && $data[$i] < $data[$i-1]; $i--) { 
                $tmp = $data[$i];
                $data[$i] = $data[$i-1];
                $data[$i-1] = $tmp;
            }
        }
    }

六. 递归行为及其时间复杂度的估算

递归函数就是系统帮你压栈,系统会按照代码的执行数序,把现场信息存储到进程控制块中。
估计递归时间复杂度的通式
master公式的使用:原始样本量为N的时间复杂度 = 子问题的样本量 + 除去子问题的样本量。
T(N) = a*T(N/b) + O(Nd)

条件 时间复杂度
logba > d O(Nlog~b~a)
logba = d O(Nd * logN)
logba < d O(Nd)

七. 归并排序

时间复杂度O(N*logN),额外空间复杂度O(N)

在这里插入图片描述
在这里插入图片描述

	// 归并排序
    protected function mergeSort(&$data)
    {
        $start = 0;
        $end = count($data) - 1;
        $this->mSort($data, $start, $end);
    }

    protected function mSort(Array &$data, $start, $end)
    {
        if ($start < $end) {
            //$mid = $start + ($end - $start) >> 1;
            $mid = floor(($start + $end) / 2);
            $this->mSort($data, $start, $mid);
            $this->mSort($data, $mid + 1, $end);
            $this->merge($data, $start, $mid, $end);
        }
    }


    protected function merge(&$data, $start, $mid, $end)
    {
        $p = $start;
        $j = $mid + 1;
        $i = $start;

        $tmpData = [];
        
        while ($p != $mid + 1 && $j != $end + 1) {
            $tmpData[$i++] = $data[$p] <= $data[$j] ? $data[$p++] : $data[$j++];
        }
        
        while ($p != $mid + 1) {
            $tmpData[$i++] = $data[$p++];
        }
        while ($j != $end + 1) {
            $tmpData[$i++] = $data[$j++];
        }
        for ($i=$start; $i <= $end; $i++) { 
            $data[$i] = $tmpData[$i];
        }
    }

八. 小和问题和逆序对问题

8.1 小和问题

在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。

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

8.2逆序对问题

<?php

namespace App\Services;
// 小和和逆序对问题
class SmallSumService
{

    public function mergeSortSum(&$data){
        if(count($data) < 2){
            return 0;
        }

        // 排序并返回最小和
        return $this->mSort($data, 0, count($data) - 1);     
    }

    public function mSort(&$data, $start, $end)
    {
        if ($start == $end) {
            return 0;
        }
        $mid = (int)floor(($start + $end) / 2);

        // 左边的最小和+右边的最小和+最后排序好的最小和就是最后的结果
        return $this->mSort($data, $start, $mid) + $this->mSort($data, $mid + 1, $end) + $this->merge($data, $start, $mid, $end);
    }

    public function merge(&$data, $start, $mid, $end)
    {
        $l = $start;
        $r = $mid + 1;
        $i = $start;
        $result = 0;
        $tmpData = [];

        while ($l != $mid + 1 && $r != $end + 1) {
            // 如果左边小于右边,那就有($r - $l + 1)个$data[$l]元素的和是最小和
            // 如果大于右边,返回0
            $result +=  $data[$l] < $data[$r] ? $l * ($end - $r + 1) : 0;
            // sum += $data[$l] > $data[$r] ? ($mid - $l + 1) : 0; //求逆序对
            $tmpData[$i++] = $data[$l] < $data[$r] ? $data[$l++] : $data[$r++];
        }

        while ($l != $mid + 1) {
            $tmpData[$i++] = $data[$l++];
        }
        while ($r != $end+ 1) {
            $tmpData[$i++] = $data[$r++];
        }

        for ($i = $start; $i < $end; $i++) { 
            $data[$i] = $tmpData[$i];
        }

        return $result; 
    }
}

猜你喜欢

转载自blog.csdn.net/DarkAngel1228/article/details/82941238