算法入门篇二 认识O(NlogN)的排序

递归

例子引出

  • 使用递归的方法求出数组中的最大值(利用的是栈)
  • 求中点的方法改进
mid = (left + right) / 2  //但是如果left和right的数很大,相加会造成内容溢出
改进为 mid = left + (right - left) / 2  //(right - left)得到整个的长度,除以2之后,再加上左边的点,就可以得到中点的位置
改进为 mid = left + (right - left) >> 1 //使用位运算,加快计算速度

代码 

package com.example.demo.class01;public class Code08_GetMax {public static void main(String[] args) {int arr[] = {1,2,4,3,2,8,6};int c = 0;c = getMax(arr);System.out.println(c);}public static int getMax(int[] arr){if(arr == null || arr.length == 0){System.out.println("输入数组不合理");}return process(arr,0,arr.length - 1);}public static int process(int[] arr,int L,int R){if(L == R){return arr[L];} //arr[L..R]只有一个数的时候,直接返回,base caseint mid = L + ((R - L)>>1);int leftMax = process(arr,L,mid);int rightMax = process(arr,mid+1,R);return Math.max(leftMax,rightMax);}
}
//8

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(N*logN)
  • 额外复杂度是O(N)
  • 代码

package com.example.demo.class01;import java.util.Arrays;public class MergeSort {public static void mergeSort(int[] arr) {if (arr == null || arr.length < 2) {return;}process(arr, 0, arr.length - 1);}public static void process(int[] arr, int L, int R) {if (L == R) {return;}int mid = L + ((R - L) >> 1);process(arr, L, mid);process(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];}}// for testpublic static void comparator(int[] arr) {Arrays.sort(arr);}// for testpublic static int[] generateRandomArray(int maxSize, int maxValue) {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;}// for testpublic 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;}// for testpublic 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;}// for testpublic 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();}// for testpublic 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);mergeSort(arr1);comparator(arr2);if (!isEqual(arr1, arr2)) {succeed = false;printArray(arr1);printArray(arr2);break;}}System.out.println(succeed ? "Nice!" : "Fucking fucked!");int[] arr = generateRandomArray(maxSize, maxValue);printArray(arr);mergeSort(arr);printArray(arr);}}

小和问题

  • 定义:在一个数组中,每一个数比前数小的数进行累加,叫做这个数的小和。
  • 转化为 (右边大于我的个数 * 我本身大小) 累加和,这个数值和小和得到的数据一致
  • res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;p1指向左边的数,p2指向右边的数,r是右边部分最右边的边界。r-p2 +1 得到比当前左边元素大的个数 ,再乘以当前元素本身;将所有元素按照上述流程进行,最后就得到了小和

  • 例子:【1,3,4,2,5】,1左边比1小的数:无;3左边比3小的数:1;4左边比4小的数:1,3;2左边比2小的数:1;5左边比5小的数:1,3,4,2;累加求和:16

使用归并排序解决小和问题

  • 归并排序,遇到相同的元素,先移动左侧,是为了保证程序的稳定性;而这里先移动右侧的元素,是为了确定比左侧指针指向的元素大的右侧区块中的元素的个数
  • 小和问题出现在三个地方:左侧区块内排序;右侧区块内排序;左右侧区块合并

代码

package class02;public class Code02_SmallSum {public static int smallSum(int[] arr) {if (arr == null || arr.length < 2) {return 0;}return process(arr, 0, arr.length - 1);}// arr[L..R]既要排好序,也要求小和public static int process(int[] arr, int l, int r) {if (l == r) {return 0;}int mid = l + ((r - l) >> 1);return process(arr, l, mid) + process(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;}// for testpublic static int comparator(int[] arr) {if (arr == null || arr.length < 2) {return 0;}int res = 0;for (int i = 1; i < arr.length; i++) {for (int j = 0; j < i; j++) {res += arr[j] < arr[i] ? arr[j] : 0;}}return res;}// for testpublic static int[] generateRandomArray(int maxSize, int maxValue) {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;}// for testpublic 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;}// for testpublic 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;}// for testpublic 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();}// for testpublic 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);if (smallSum(arr1) != comparator(arr2)) {succeed = false;printArray(arr1);printArray(arr2);break;}}System.out.println(succeed ? "Nice!" : "Fucking fucked!");}}
  • 类似于逆序对问题:如果左边的数比右边的数大,则二者构成一个逆序对,原理类似
  • res += arr[p1] > arr[p2] ? (m - p1 +1) : 0;
    

荷兰国旗问题

  • 快速排序 
  • 给定数组arr和数num,将小于等于num的数放在数组的左边,大于num的数放在数组的右边,要求时间复杂度为O(N),空间复杂度为O(1);不要求内部有序

  • 将数组分为三个部分,以num为界限,分为小于等于区、大于区和待定区。指针指向数组的第一个元素,判定指针指向的元素是否小于等于num,如果成立当前数和小于等于区的下一个数交换,然后小于等于区向右移动,指针也向右移动
  • 如果指针指向的元素大于num,那么指针直接跳过该元素,向右移动。
package class02;public class Code05_NetherlandsFlag {public static int[] partition(int[] arr, int l, int r, int p) {int less = l - 1;int more = r + 1;while (l < more) {if (arr[l] < p) {swap(arr, ++less, l++);} else if (arr[l] > p) {swap(arr, --more, l);} else {l++;}}return new int[] { less + 1, more - 1 };}// for testpublic static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}// for testpublic static int[] generateArray() {int[] arr = new int[10];for (int i = 0; i < arr.length; i++) {arr[i] = (int) (Math.random() * 3);}return arr;}// for testpublic 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();}public static void main(String[] args) {int[] test = generateArray();printArray(test);int[] res = partition(test, 0, test.length - 1, 1);printArray(test);System.out.println(res[0]);System.out.println(res[1]);}
}

第二个问题

  • 荷兰国旗问题:给定数组arr和数num,将小于等于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边,要求时间复杂度为O(N),空间复杂度为O(1)

  • 将数组分为三个部分,小于区、中间区和大于区。
  • 首先用指针指向数组的第一个元素,如果当前指向的数小于num,则小于区下一个元素和当前数值侧面交换,小于区域向右边扩,指针向右边移动
  • 如果当前指针指向的元素和num相等,那么指针直接跳过,移动到下一个位置
  • 如果当前指针指向的元素大于num,那么大于区的前一个元素和当前指针指向的元素交换,大于区域向左边扩展,但是当前指针不可以移动位置,因为,交换了元素,不知道这个交换元素和num的大小
package class02;import java.util.Arrays;public class Code06_QuickSort {public static void quickSort(int[] arr) {if (arr == null || arr.length < 2) {return;}quickSort(arr, 0, arr.length - 1);}public static void quickSort(int[] arr, int l, int r) {if (l < r) {swap(arr, l + (int) (Math.random() * (r - l + 1)), r);int[] p = partition(arr, l, r);quickSort(arr, l, p[0] - 1);quickSort(arr, p[1] + 1, r);}}public static int[] partition(int[] arr, int l, int r) {int less = l - 1;int more = r;while (l < more) {if (arr[l] < arr[r]) {swap(arr, ++less, l++);} else if (arr[l] > arr[r]) {swap(arr, --more, l);} else {l++;}}swap(arr, more, r);return new int[] { less + 1, more };}public static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}// for testpublic static void comparator(int[] arr) {Arrays.sort(arr);}// for testpublic static int[] generateRandomArray(int maxSize, int maxValue) {//l到r随机选一个数做等概率划分 ,最差情况发生概率下降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;}// for testpublic 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;}// for testpublic 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;}// for testpublic 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();}// for testpublic 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);quickSort(arr1);comparator(arr2);if (!isEqual(arr1, arr2)) {succeed = false;printArray(arr1);printArray(arr2);break;}}System.out.println(succeed ? "Nice!" : "Fucking fucked!");int[] arr = generateRandomArray(maxSize, maxValue);printArray(arr);quickSort(arr);printArray(arr);}}
  • 快排的时间复杂度是 o(N*logN)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/447227.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法入门篇三 详解桶排序和整理排序知识 堆的相关操作 补充 不完整

归并排序不使用递归 使用一个变量&#xff0c;使其按照1、2、4、8递增&#xff0c;控制左右两边1个元素、2个元素、4个元素等元素的合并 完全二叉树 完全二叉树 要不全是满的&#xff0c;要不叶子节点出现在最后一层&#xff0c;只要出现了叶子节点&#xff0c;后面的都是叶子…

2023年12月24日学习总结

今日to do list&#xff1a; 做kaggle上面的流量预测项目☠️ 学习时不刷手机&#x1f921; okkkkkkkkkkkkkk 开始&#x1f44d;&#x1f34e; 0、我在干什么&#xff1f; 我在预测一个名字叫做elborn基站的下行链路流量&#xff0c;用过去29天的数据预测未来10天的数据 1、…

Mac/Linux系统连接远端服务器以及相同IP地址的服务器账号密码重置,ssh失败问题

连接远端服务器 ssh 账号IP地址 输入完成之后会提示输入密码&#xff0c;密码输入正确后&#xff0c;就可以连接成功了 重置ssh密钥 如果连接的服务器除了IP地址没有改变&#xff0c;其余的账号、密码、系统等都变了的话&#xff0c;因为曾经连接过的历史数据会保存到本地&a…

Linux操作系统监视NVIDIA的GPU使用情况

对于GPU相关参数介绍 使用命令周期性查看GPU运行情况最常用的参数是 -n&#xff0c; 后面指定是每多少秒来执行一次命令。监视显存&#xff1a;设置为每 1s 显示一次显存的情况&#xff1a;使用命令ctrlz退出 watch -n 1 nvidia-smi 参数介绍 Fan&#xff1a;显示风扇转速&am…

算法入门篇四 桶排序

桶排序 计数排序&#xff08;基于统计&#xff09; 要求数据是有限的&#xff0c;和数据状况有关&#xff0c;比如对于200个人统计他们的年龄分布&#xff0c;这个时候需要申请200个桶&#xff0c;因此对于输入数据的规模有限制&#xff0c;如果输入规模是不定的&#xff0c;…

RTP概述

1.1. RTP是什么 RTP全名是Real-time Transport Protocol&#xff08;实时传输协议&#xff09;。它是IETF提出的一个标准&#xff0c;对应的RFC文档为RFC3550&#xff08;RFC1889为其过期版本&#xff09;。RFC3550不仅定义了RTP&#xff0c;而且定义了配套的相关协议RTCP&…

算法入门篇五 链表

牛客网 算法入门篇 判断一个链表是否为回文结构 给定一个单链表的头节点head&#xff0c;请判断这个链表是否为回文结构1->2->1&#xff0c;返回为True;1->2->3为False 思路&#xff1a; 1&#xff0c;遍历链表&#xff0c;将所有元素压入栈中&#xff0c;然后再…

实时流媒体编程基于Linux环境开发

一、流媒体简介 随着Internet的日益普及&#xff0c;在网络上传输的数据已经不再局限于文字和图形&#xff0c;而是逐渐向声音和视频等多媒体格式过渡。目前在网络上传输音频/视频&#xff08;Audio/Video&#xff0c;简称A/V&#xff09;等多媒体文件时&#xff0c;基本上只有…

算法入门篇六 二叉树

牛客网 算法入门篇 左程云老师 个人复习&#xff0c;如果侵全&#xff0c;设为私密 二叉树遍历&#xff08;递归&#xff09; 先序遍历&#xff08;中&#xff0c;左&#xff0c;右&#xff09; 中序遍历&#xff08;左&#xff0c;中&#xff0c;右&#xff09; 后序遍历&a…

算法入门篇七 前缀树

牛客网 左程云老师的算法入门课 找二叉树的节点的后继节点 原则 如果节点有右子树&#xff0c;那么后继节点就是右子树的最左边的第一个节点如果节点没有右子树&#xff0c;如果节点是父节点的右孩子&#xff0c;就继续往上找&#xff0c;直到找到一个父节点是沿途节点的父节…

算法入门篇八 贪心算法

牛客网 左程云老师的算法入门课 贪心算法 贪心算法的解题步骤 例子 题目要求 解题策略 按照结束时间早的会议先安排&#xff0c;比如先安排【2&#xff0c;4】&#xff0c;当4结束了&#xff0c;所有开始时间小于4的全部淘汰&#xff0c;【1&#xff0c;7】、【3&#xff…

算法入门篇九 暴力递归

牛客网 左程云老师的算法入门课 暴力递归 原则 汉诺塔问题 问题 打印n层汉诺塔从左边移动到最右边的过程 思想 一共六个过程&#xff0c;左到右、左到中&#xff0c;中到左&#xff0c;中到右&#xff0c;右到左&#xff0c;右到中&#xff0c;互相嵌套使用 左到右 将1…

rtsp和sdp

RTSP 是由Realnetwork 和Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层协议 。 实时流协议&#xff08;RTSP&#xff09;建立并控制一个或几个时间同步的连续流媒体&#xff0c;如音频和视频。尽管连续媒体流与控制流交叉是可能的&#xff0c;RTSP本身并不发…

使用javascript实现对于chineseocr的API调用

ChineseOCR在线API 网页地址 界面 提供多种接口调用方式&#xff0c;比如在线调用、Javascript api调用、curl api调用和python api调用四种方式&#xff0c;本次使用javascript api调用的方式进行OCR识别在线Javascript工具 在线工具网页链接在线Base64 转化工具 在线工具…

移动流媒体业务的技术与标准

1 引言   流媒体业务是从Internet上发展起来的一种多媒体应用&#xff0c;指使用流&#xff08;Streaming&#xff09;方式在网络上传输的多媒体文件&#xff0c;包括音频、视频和动画等。   流媒体传输技术的主要特点是以流&#xff08;streaming&#xff09;的形式进行多…

使用python实现对于chineseocr的API调用

ChineseOCR在线API 网页链接 界面 提供多种接口调用方式&#xff0c;比如在线调用、Javascript api调用、curl api调用和python api调用四种方式&#xff0c;本次使用javascript api调用的方式进行OCR识别在线Base64 转化工具 Base64在线小工具代码修改 新增一个变量fill_w…

算法入门篇十 图

图的存储方式 临接表临接矩阵 表达 点集/边集有向图/无向图 Graph&#xff08;大结构就是图&#xff09;&#xff08;包含点集合和边集合&#xff09; import java.util.HashMap; import java.util.HashSet;public class Graph {public HashMap<Integer, Node> nodes;…

超文本传输协议

超文本传输协议 超文本传输协议超文件传输协定(HTTP&#xff0c;HyperTextTransfer Protocol)是因特网上应用最为广泛的一种网络传输协定。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。 目录 介绍请求信息请求方法安全方法超…

利用MFC调用libvlc.dll作一个简单的播放器

简单介绍MFC调用libvlc.dll作一个简单的播放器&#xff0c;抛砖引玉&#xff0c;各位VC达人继续深入研究&#xff0c;Jeremiah对VC确实不太感兴趣&#xff0c;所以就不做太深入的研究了。2009.10.29修改&#xff1a;加入clip_children属性设置。参开第1步。环境&#xff1a; …

使用Remix编写Solidity语言的小例子

设置数值/取数值/加法运算 讲解 uint默认使用256位数的整型view表示这个函数仅仅对于数据仅仅是读取&#xff0c;没有修改操作returns(uint )&#xff0c;如果单纯指定uint&#xff0c;返回的是函数体内的return值&#xff0c;如果包含uint sum,uint SAD_a&#xff0c;那么返…