基本排序算法

冒泡排序

没什么可说的, 改进方法就是加一个标志位防止有序后重复遍历. 由于需要遍历两次, 所以时间复杂度O(N^2)

选择排序

外层从0开始默认outer是最小数的下标, 内存从outer+1位置开始遍历, 不稳定, 如{ 3, 3, 3, 2 }, 当比较最后一个4时, 是第一个3和2交换, 从而不稳定. 内外层遍历两次, 时间复杂度O(N^2)

插入排序

相当于打扑克排序, outer从1到N-1, inner从outer到N-1, 时间复杂度O(N^2)

插入排序选择排序冒泡排序有浪费许多比较的次数

归并排序快的是因为小范围合并为大范围时, 有序可以同过外排方式

小组和为大组时, 组内有序没有浪费, 永远是组与组之间的比较

希尔排序

归并排序

递归把一个数字分隔为两部分, T(N) = 2*T(N/2) + O(N), a= 2, b = 2, N = 1, 时间复杂度O(N*logN), 额外空间复杂度O(N)

递归符合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)

快排

递归公式同归并排序, 由于需要记录分隔点, 所以额外空间复杂度O(logN), 快排做不到稳定性, 因为partition过程做不到稳定

  1. 经典快排与数据状况有关, 这是因为分隔点选取的问题, 如{1, 2, 3, 4, 5, 6}分隔点选取最右边时每次只排序一个数字, 此时时间复杂度为O(N^2)
  2. 如果分隔点选取中位数, 则每次恰好可把数组划分为两部分, 时间复杂度为O(N*logN)
  3. 随机快排的分隔点随机选取, 把复杂度转化为与概率有关, 复杂度长期期望为O(N*logN)

堆排

大根堆结构重要两个函数heapInsert与heapify, 一个上浮, 一个是下沉, 优先级队列就是堆

建立堆的时间复杂度为O(log1) + O(log2) + O(log3) + ... + O(log(N)), 收敛域O(N)

  • 算法: 插入时, 上浮, 直至没有父节点比当前节点大; 排序交换堆顶与堆未元素, 这时堆顶元素下沉, 直至当前节点比子节点都大
  • 传送门 --> 堆排

排序补充

  1. 归并排序可以做到额外空间复杂度O(1), 有难度, 相关搜索"归并排序内部缓存法"
  2. 快排可以做到稳定性, 有难度, 不要求掌握, 相关搜索"01 stable sort"; 快排的优势是partition过程中, 时间复杂度O(N), 空间复杂度O(1)
  3. 有一道题目, 奇数放在数组的左边边, 偶数放在数组右边, 要求原始的相对次数不变, 牛客练习 --> 调整数组顺序使奇数位于偶数前面

排序总结

排序方法 平均情况 最好情况 最坏情况 辅助空间 稳定性
冒泡排序 O(N^2) O(N) O(N^2) O(1) 稳定
选择排序 O(N^2) O(N^2) O(N^2) O(1) 不稳定
插入排序 O(N^2) O(N) O(N^2) O(1) 稳定
希尔排序 O(N*logN) ~ O(N^2) O(N^1.3) O(N^2) O(1) 不稳定
堆排序 O(N*logN) O(N*logN) O(N*logN) O(1) 不稳定
归并排序 O(N*logN) O(N*logN) O(N*logN) O(N) 稳定
快排 O(N*logN) O(N * logN) O(N^2) O(logN) ~ O(N) 不稳定

工程中的综合排序算法

基础类型很长时, 使用快排, 因为基础数据类型不要求稳定

复合数据类型长度很长时, 使用归并排序, 复合数据类型要求稳定

任何数据类型的数组长度很短(<60)时, 使用插入排序

桶排序

桶排序是一个逻辑概念, 具体实现方法是计算排序, 基数排序

  1. 非基于比较的排序, 与被排序的样本的实际数据状况有很大关系, 所以实际中并不经常使用
  2. 时间复杂度O(N), 额外空间复杂度O(N)
  3. 稳定

计算排序

基数排序

一个有序数组A, 另一个无序数组B, 打印B中所有不在A中的数组, A数组长度为N, B数组长度为M

  • 算法1: 暴力法, 时间复杂度O(N^2)
  • 算法2: 遍历B数组, 使用二分法在A中查找相同元素, 时间复杂度O(M * logN)
  • 算法3: 把A数组进行排序, 排序最小时间复杂度O(M*logM), 使用类似外排进行排序, 总时间复杂度O(M*logM) + O(M+N)

    两个游标, p1指向A, p2指向B

    (1) A[p1] < B[p2]; p1++

    (2) A[p1] == B[p2]; p1不移动, 移动p2, 因为B数组中可能有重复数字所以只移动p2

    (3) A[p1] > B[p2]; 打印并移动p2
  • 传送门 --> 时间复杂度理解

使用递归查找数组中的最大值

  • 算法: 二分法查找分隔数字, 返回左右数组中的最大值

    本算法中T(N) = 2*T(N/2) + O(1), a=b=2, d=0, log(2, 2)=1 > d=0, 复杂度为O(N^log(2, 2))=O(N)
  • 传送门 --> 使用递归查找最大值

小和

在一个数组中, 每一个数左边比当前数小的数累加起来, 叫做这个数组的小和. 求一个数字的小和. 如[1, 3, 4, 2, 5]小和为16

  • 算法: 利用归并排序, 关键步骤res += (arr[lowPtr] < arr[hightPtr] ? arr[lowPtr] * (right - hightPtr + 1) : 0);其中arr[lowPtr] * (right - hightPtr + 1) 是关键, 和归并排序一样, 没有浪费之前的比较次数

    本题递归公式T(N) = 2*T(N/2) + O(N), 时间复杂度同归并排序, 同位O(N*logN)
  • 传送门 --> 小和

逆序对

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

  • 算法: 与小和相同, 只是在merge时把数组从大到小排列, 关键步骤res += (vt[leftPtr] > vt[rightPtr] ? (right - rightPtr + 1) : 0);与上述相差大小号和乘一个数区别, 目前只能统计个数, 打印有些问题
  • 传送门 --> 逆序对
  • 牛客练习 --> 数组中的逆序对

荷兰国旗问题

给定一个数组arr, 和一个数num, 请把小于num的数放在数组的左边, 等于num的数放在数组的中间, 大于num的数放在数组的右边, 要求额外空间复杂度O(1), 时间复杂度O(N)

  • 算法: 准备三个游标leftPtr初始指向数组边界起始位置前一个元素即left-1, rightPtr初始指向末尾后一个元素right+1, index从头到尾遍历数组比较

    (1) 比num小, index指向元素和leftPtr指向的下一元素交换, index和leftPtr同时+1

    (2) 等于num, 只把index+1

    (3) 大于num, 把index元素和rightPtr指向的元素前一个交换, rightPtr-1, 由于不确定rightPtr指向元素和num的关系, index不变
  • 传输门 --> 荷兰国旗问题

数据流的中位数

实质利用堆排序找中位数

排序数组最大差值

给定一个数组, 求排序之后相邻两数的最大差值, 要求时间复杂度O(N), 且要求使用非基于比较的排序

  • 算法: 运用桶的概念. N个数, 准备N+1个桶, 最小值放0号桶, 最大桶放N号桶放N号桶;

    三个数组, 分别记录桶是否有值, 桶内最大值, 桶内最小值; 相邻两个数最大差值可能存在于两个非空桶之间, 也可能存在于空桶之间
  • 传输门 --> 排序数组最大差值

数据流中位数

如何可以得到数据流中排序后的中位数

用数组结构实现大小固定栈

用数组结构实现大小固定队列

  • 算法: 使用三个变量: start, end, size. 目的是为了是start和end解耦合, 使start只与size有关, end只与size有关.

    插入只与m_size和m_arraySize有关, 弹出只与m_size和0有关; 弹出直接弹出m_start位置的元素, 插入直接插入到m_end位置

    m_start的变化只与m_arraySize有关; m_end的变化只与m_arraySize有关. m_start与m_end都是+1递增
  • 传输门 --> 数组实现大小固定的队列

仅用队列结构实现栈结构

传送门 -->

仅用栈结构实现队列结构

双栈返回最小值

实现一个特殊的栈, 在实现栈的基本功能的基础上, 再实现返回栈中的最小元素的操作. 要求: 1. pop, push, getMin操作的时间复杂度都是O(1); 2. 设计的栈类型可以使用现成的栈结构

顺时针打印矩阵

给定一个整型矩阵matrix, 按照从外向里以顺时针的顺序依次打印出每一个数字. 例如:如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

旋转正方形

给定一个整型正方形矩阵matrix, 把该矩阵调整成顺时针转换90度的样子. 额外空间复杂度O(1)

  • 算法: 同顺时针打印矩阵一样, 抽象一个顺时针打印边框的函数, 从外到内依次调用这个函数.
  • 传送门 --> 旋转正方形矩阵

之字形打印矩阵

给定一个矩阵matrix, 按照"之"字形方式打印这个矩阵

  • 算法: 抽象一个打印斜行的矩阵, 通过一个布尔变量来判断从上到下还是从下到上, 调用函数多了些边界判断. x_1和y_1, x_2和y_2先后移动次序有很大关系, 先比较x_1再判断y_1, 先比较y_2再判断x_2,
  • 传输门 --> 之字形打印矩阵

行列有序的矩阵中查找

给定一个由N*M的整数型矩阵matrix和一个整数K, matrix的每一行和每一列都是排好序的. 实现一个函数, 判断K是否在matrix中. 要求时间复杂度O(N+M), 额外空间复杂度O(1)

  • 算法: 从矩阵的特性出发, 确定查找方法. 设置查找起始点设置为右上角

      若K小于右上角的数, 则不可能在当前列的下面, 左移起始点

      若K大于右上角的数, 则不可能在当前行的左边, 下移起始点
  • 传送门 --> 行列有序的矩阵中查找
  • 牛客练习 --> 二维数组中的查找

链表面试与笔试

链表问题往往在空间复杂度上下工夫, 时间复杂度基本是O(N)或O(N^2)

笔试: 目的最快把问题过掉, 不追求空间复杂度

面试: 和面试官聊空间复杂度

分别实现反转单向链表和反转双向链表函数

  • 算法: 分别定义两个指针, next和pre, 当head不为空时, next和pre都初始化为nullptr

    (1)next指向head下一节点

    (2)利用pre与head反转单/双链表

    (3)使pre指向head

    (4)使head指向next
  • 递归反转单链表:

    (1)递归到最后一个节点, 然后依次返回

    (2)当前节点的下一节点的next指向当前节点

    (3)当前节点的next域指向nullptr
  • 传送门 --> 反转单双链表
  • 牛客练习 --> 反转链表

判断一个链表是否是回文结构

给定一个链表的头结点head, 判断该链表是否是会问结构. 如: 1, 2, 1返回true; 1, 2, 2, 1返回true; 1, 2, 3返回false. 如果求时间复杂度O(N), 额外空间复杂度O(1)

  • 算法1: 使用栈把元素逆序, 遍历两次列表, 第一次压栈, 第二次和栈中元素对比是否相同, 时间复杂度O(N), 空间复杂度O(N)
  • 算法2: 使用快慢指针

单向链表划分

将单向链表按某值划分成左边小, 中间相等, 右边大的形式

复制含有随机指针节点的链表

两个连续相交问题

给定三角形ABC和一点P(x,y,z),判断点P是否在ABC内,给出思路并手写代码

  • 面积计算公式及浮点数的比较
#include <iostream>
#include <math.h>
using namespace std;
#define ABS_FLOAT_0 0.0001 // 浮点数比较
struct point_float {
float x;
float y;
}; float GetTriangleSquar(const point_float pt0, const point_float pt1, const point_float pt2) {
point_float AB, BC;
AB.x = pt1.x - pt0.x;
AB.y = pt1.y - pt0.y;
BC.x = pt2.x - pt1.x;
BC.y = pt2.y - pt1.y;
return fabs((AB.x * BC.y - AB.y * BC.x)) / 2.0f;
} bool IsInTriangle(const point_float A, const point_float B, const point_float C, const point_float D){
float SABC, SADB, SBDC, SADC;
SABC = GetTriangleSquar(A, B, C);
SADB = GetTriangleSquar(A, D, B);
SBDC = GetTriangleSquar(B, D, C);
SADC = GetTriangleSquar(A, D, C);
float SumSuqar = SADB + SBDC + SADC;
if ((-ABS_FLOAT_0 < (SABC - SumSuqar)) && ((SABC - SumSuqar) < ABS_FLOAT_0))
return true;
else
return false;
}

n个整数的无序数组,找到每个元素后面比它大的第一个数,要求时间复杂度为O(N)

vector<int> findMax(vector<int>num)
{
if(num.size()==0)return num;
vector<int>res(num.size());
int i=0;
stack<int>s;
while(i<num.size())
{
if(s.empty()||num[s.top()]>=num[i])
{
s.push(i++);
}
else
{
res[s.top()]=num[i];
s.pop();
}
}
while(!s.empty())
{
res[s.top()]=INT_MAX;
s.pop();
}
for(int i=0; i<res.size(); i++)
cout<<res[i]<<endl;
return res;
}

fasd的更多相关文章

  1. Quora的技术探索(转)

    原文:http://www.cnblogs.com/xiekeli/archive/2012/04/27/2473808.html 关于问答类的应用,最早接触的是stackoverflow和知乎 ,而 ...

  2. springmvc(六)——视图和视图解析器

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoIAAAGrCAIAAADb2WEhAAAgAElEQVR4nOzdaVhTd78vfF8/z772c9 ...

  3. php基础知识【函数】(1)数组array

    一.排序 1.sort -- 从最低到最高排序,删除原有的键名,赋予新的键名[字母比数字高] 2.rsort -- 逆向排序(最高到最低),删除原有的键名,赋予新的键名[字母比数字高] 3.asort ...

  4. 那些我希望在一开始使用 Zsh(oh-my-zsh) 时就知道的

    原文地址:http://segmentfault.com/a/1190000002658335  作者:xavier 自带的插件 其实我用了 oh-my-zsh 快三个月后才知道原来他自带了很多插件没 ...

  5. amazeui 搜索 动态

    <!doctype html> <html class="no-js"> <head> <meta charset="utf-8 ...

  6. 模糊搜索神器fzf

    前言 fzf是目前最快的fuzzy finder.使用golang编写.结合其他工具(比如ag和fasd)可以完成非常多的工作. 让你通过输入模糊的关键词就可以定位文件或文件夹.当你的思维也习惯了模糊 ...

  7. Python系列之正则表达式详解

    Python 正则表达式模块 (re) 简介 Python 的 re 模块(Regular Expression 正则表达式)提供各种正则表达式的匹配操作,和 Perl 脚本的正则表达式功能类似,使用 ...

  8. Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)&&Codeforces 861C Did you mean...【字符串枚举,暴力】

    C. Did you mean... time limit per test:1 second memory limit per test:256 megabytes input:standard i ...

  9. Python基础练习题100例(Python 3.x)

    1:题目:有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 程序源 ...

随机推荐

  1. 076 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 01 Java面向对象导学

    076 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 01 Java面向对象导学 本文知识点:Java面向对象导学 说明:因为时间紧张,本人 ...

  2. DOS批处理中%cd%与%~dp0的区别详解

    转载:https://www.jb51.net/article/105325.htm DOS批处理中%cd%与%~dp0的区别详解     Windows下批处理中%cd%和%~dp0都能用来表示当前 ...

  3. 头文件afx.h作用

    转载:https://blog.csdn.net/OnceMonkeyG/article/details/95723290 一些定义与设置,为MFC提供最基本支持,将各种松散的东西组织起来,同时为MF ...

  4. 电机AB相编码器测速

    控制任务 检测编码器的脉冲并测速 电路设计 图1 直流电机带减速器和编码器 图2  编码器接线定义 编码器接线定义如下 M1:电机电源接口,绿色的 GND:编码器电源负极输入口,橙色的 C1:编码器A ...

  5. 程序员你是如何使用Nacos作为配置中心的?

    假如你使用的是spring-cloud-alibaba微服务技术栈 单个服务独有配置文件 即去除应用程序的状态,配置统一外部化管理,方便进行水平的伸缩. 集成步骤: 假如我有一个应用app-desig ...

  6. BeetleX之webapi使用入门

    BeetleX是TCP通讯应用组件,在它之上可以扩展任何基于TCP的应用通讯功能.FastHttpApi是组件扩展的一个Http/Https/Websocket服务组件,它提供的功能丰富,包括功能有: ...

  7. ansible-playbook-roles目录结构

    1. ansible-角色-roles目录结构       角色是基于已知文件结构自动加载某些vars_files,任务和处理程序的方法.按角色对内容进行分组还可以轻松与其他用户共享角色.      ...

  8. git add 添加错文件如何撤销

    git add 添加 多余文件 这样的错误是由于, 有的时候 可能 git add . (空格+ 点) 表示当前目录所有文件,不小心就会提交其他文件 git add 如果添加了错误的文件的话 以下是撤 ...

  9. FastJson解析Json,封装JavaBean对象

    获取到前端的Json,后台对应封装JavaBean对象,对其解析赋值 获取到前端的json,对其进行分析 1.获取最外层前端json对应得JavaBean (1)未分析格式的json串 (2)初步格式 ...

  10. MeteoInfoLab脚本示例:线性拟合

    MeteoInfoLab提供一个线性拟合函数linregress,参数是参与拟合的两个数据序列,返回拟合的斜率.截距和相关系数.有了上述拟合参数可以用polyval函数生成拟合数据(直线).然后可以将 ...