算法入门篇 一 时间复杂度

时间复杂度

  • 要求:只要高阶项,不要低阶项
  • 常数操作:操作花费的时间和数据量无关,比如数组寻址,直接利用偏移量找到对应元素的位置;
  • 非常数操作:比如list(链表);查找元素需要遍历链表,元素查找时间和元素对应的位置有关;时间复杂度为O(n)
  • 常数时间操作:两个数相加(+)  相减(-) 左移(<<)  右移(>>) 或运算(|) 与运算(&) 异或运算(^) 

例子  选择排序  引出时间复杂度

package class01;import java.util.Arrays;public class Code01_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;}// 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);selectionSort(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);selectionSort(arr);printArray(arr);}}
  • 选择排序:先从[0->N-1]范围内找最小值,对于每个位置上元素的操作时间为c;再从[1->N-1]、[2->N-1]、[3->N-1]等,所以一共需要花费时间为((N)+(N-1)+(N-2)+  + (1))*c = (aN^2 + b*N + k)*c = acN^2 + bcN + kc 只要高阶项,不要低阶项,也不要高阶项的系数,时间复杂度为N^2,即O(N^2)
  • 一个操作如果和样本数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作
  • 表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,剩下的部分如果是f(N),那么时间复杂度就是O(f(N))
  • 评价一个算法的好坏,先看时间复杂度指标,然后分析不同数据样本下的实际运行时间,也就是“常数项时间” 

冒泡排序

  • 最差情况 每个位置上元素都需要移动
package class01;import java.util.Arrays;public class Code02_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];}// 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);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);}}

插入排序

  •  时间复杂度 按照最差情况计算
  • 插入排序 和数据情况有关,因此相较于冒泡排序和选择排序 会好
package class01;import java.util.Arrays;public class Code03_InsertionSort {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];}// 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);insertionSort(arr1);comparator(arr2);if (!isEqual(arr1, arr2)) {succeed = false;break;}}System.out.println(succeed ? "Nice!" : "Fucking fucked!");int[] arr = generateRandomArray(maxSize, maxValue);printArray(arr);insertionSort(arr);printArray(arr);}}

二分查找

  • 每次都是找中点,比较数据,因此时间复杂度是  O(log2N)

在一个有序数组中,找某个数是否存在?二分查找

package com.example.algorithm.demo.class1;import java.util.Arrays;public class Code04_BSExist {public static boolean exist(int[] sortedArr,int num){if (sortedArr == null || sortedArr.length == 0){return false;}int L = 0;int R = sortedArr.length - 1;int mid = 0;while (L < R){mid = L +((R - L) >> 1);if (sortedArr[mid] == num){return true;} else if (sortedArr[mid] > num){R = mid - 1;} else {L = mid + 1;}}return sortedArr[L] == num;}// for testpublic static void comparator(int[] arr) {Arrays.sort(arr);}// for testpublic static void printArray(int[] arr){for (int i = 0;i < arr.length;i++){System.out.print(arr[i] + " ");}}public static void main(String[] args) {int[] arr = {1,2,5,3,1,6,78,9,234,55,666,76};comparator(arr);printArray(arr);System.out.println();if (exist(arr,234)){System.out.println("存在数据!");} else {System.out.println("不存在数据!");}}
}

在一个有序数组中,找大于等于某个数最左侧的位置?(进一步演化)

  • 比如 1223334444555556666667777777
package com.example.algorithm.demo.class1;import java.util.Arrays;public class Code05_BSNearLeft {//在arr上 找到满足>=value的最左位置public static int nearestIndex(int[] arr,int value){int L = 0;int R = arr.length - 1;int index = -1;while (L < R){int mid = L + ((R - L) >> 1);if (arr[mid] >= value){index = mid;R = mid - 1;} else {L = mid + 1;}}return index;}// for testpublic static void comparator(int[] arr) {Arrays.sort(arr);}// for testpublic static void printArray(int[] arr){for (int i = 0;i < arr.length;i++){System.out.print(arr[i] + " ");}}public static void main(String[] args) {int[] arr = {1,23,4,5,5,5,6,7,7,8,8,8,8,2,1,2,4,5,3,1,6,78,9,234,55,666,76};comparator(arr);printArray(arr);System.out.println();System.out.println("元素7的位置索引是"+ (nearestIndex(arr,7)+1));}
}

额外空间复杂度

  • 使用辅助数组,额外空间就不是O(1)

局部最小

  • 要求:无序数组,相邻不等,返回一个局部最小的位置,怎么整?
  • 具体操作:1,先看0位置的元素,如果0位置小于1位置,那么直接返回1位置的元素;2,上一条件不满足,即0位置元素大于1位置的元素,则看N-1位置的元素是否是局部最小,如果是直接返回。如果不是,则表明N-2位置的元素小于N-1位置的元素。表明0-1曲线下降,N-2  到 N-1 曲线上升,表明在0->(N-1)绝对存在局部最小。数学知识
  • 编码:使用二分搜索,判断局部最小;

原理

  • 【0】<【1】,0是局部最小
  • 【N-1】<【N-2】,N-1是局部最小
  • 【i-1】<【i】<【i+1】,i是局部最小

方法

  • 二分法,在0-N一定存在局部最小
  • 二分不一定只能适用于有序数组,这个和题意有关。比如查找一个局部最小的数值

异或计算(无进位相加

  • 0异或N=N  N异或N=0
  • 满足交换律和结合律(具体操作和执行的次序无关)

完成数据的交换

  • 引入第三方变量
int a = 1;
int b = 2;
int c = a;
a = b;
b = c;
  • 单独自身计算,不引入第三方变量
int a = 1;
int b = 2;
a = a + b; //a = 3
b = a - b; //b = 3 - 2 = 1
a = a - b; //a = 3 - 1 = 2
  •  使用异或(前提,值是一样的,但是a和b所处的内存区域是不同的,如果相同会出错)相同会导致数据抵消,二者都变成0
int a = 1;
int b = 2;
a = a 异或 b; //a = 1 异或 2,b = 2
b = a 异或 b; //a = 1 异或 2, b = 1
a = a 异或 b; //a = 1 异或 2 异或 1 = 2, b = 1即使a和b的元素都是2,也可以实现数据的交换,但是如果a和b指向相同的地址空间,会消除数据,a和b都变成0
  • 错误使用 
  • i和j指向相同的位置,造成数据抹除
int[] arr = {4,5,3}
int i = 0;
int j = 0;arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];for(int c = 0; c < arr.length; c++){System.out.println(arr[c]);
}arr[0]=0;arr[1]=5;arr[2]=3;

1,一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数 

public static void printOddTimesNum1(int[] arr){int eor = 0;for (int cur : arr){eor ^= cur;}System.out.println(eor);
}
  • 只有一个是奇数项,将所有元素都异或,相同元素就会消失,只剩下奇数的元素,利用到了异或的交换律和结合律

2,一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数 例子

【1011,0110,0110,1011,1000,0001】
1,让所有元素异或运算,得到eor变量,这个利用相同位置上1的个数,如果是奇数个,则为1,同理,偶数个1为0
2,第一步得到的eor=1001,因为eor的末尾元素为1,则将所有末尾为1的元素进行第二次异或,得到eor’,具体是【1011,1011,0001】,则eor'=0001,eor'也为第一个奇数个元素
3,将eor和eor'进行异或,eor=1001,eor'=0001,则二者计算得到1000为第二个奇数个的元素

引出新的问题 

  • 上面例子中的eor=1001,我们提取最后面位置上的元素 1,是如何实现的呢?
  • 例子(方法1)
01101000如何操作变成00001000呢?提取到指定位数的1,其余位数全部清零
假设 a = 01101000
1,计算 a-1,目的是打散最末尾的数字1,a-1 = 01100111
2,计算 a同或a-1 = 01100000,目的是清楚原始最右侧的1
3,计算 a异或(a同或a-1)= 00001000
  • 例子(方法2)

a & (~a +1)
a = 01101000, a取反得到10010111,再 +1 得到10011111
a & (~a +1) = 01101000 & 10011111 = 00001000
获取最右边的 1

步骤

  •  先将所有的元素进行异或,使用eor 得到 奇数 a 和 b 的异或,即 eor = a ^ b;
  • 将eor转化为二进制,其中位置为1 的用于区别a 和 b;假设x位置上元素为1,将数组中元素x位置为1的全部进行异或得到eor‘;eor’ = a或者b
  • 再将 eor和 eor‘ 异或得到另外一个元素

代码

public static void printOddTimesNum2(int[] arr){int eor = 0;for (int i=0;i<arr.length;i++){eor ^= arr[i];//eor = a ^ b//err != 0//err必然有一个位置上是1int rightOne = eor & (~eor + 1);//提取出最右侧的1int onlyOne = 0;//eor'for (int cur : arr){if((cur & rightOne) == 0){onlyOne ^= cur;}}}System.out.println(onlyOne + " " + (eor ^ onlyOne));
}
package class01;public class Code07_EvenTimesOddTimes {public static void printOddTimesNum1(int[] arr) {int eO = 0;for (int cur : arr) {eO ^= cur;}System.out.println(eO);}public static void printOddTimesNum2(int[] arr) {int eO = 0, eOhasOne = 0;for (int curNum : arr) {eO ^= curNum;}int rightOne = eO & (~eO + 1);for (int cur : arr) {if ((cur & rightOne) != 0) {eOhasOne ^= cur;}}System.out.println(eOhasOne + " " + (eO ^ eOhasOne));}public static void main(String[] args) {int a = 5;int b = 7;a = a ^ b;b = a ^ b;a = a ^ b;System.out.println(a);System.out.println(b);int[] arr1 = { 3, 3, 2, 3, 1, 1, 1, 3, 1, 1, 1 };printOddTimesNum1(arr1);int[] arr2 = { 4, 3, 4, 2, 2, 2, 4, 1, 1, 1, 3, 3, 1, 1, 1, 4, 2, 2 };printOddTimesNum2(arr2);}}

 对数器

  • 最简单的方法和优化的方法,使用大量的结果分别测试,如果结果是一致的,说明优化的方法是正确的。

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

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

相关文章

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

递归 例子引出 使用递归的方法求出数组中的最大值&#xff08;利用的是栈&#xff09;求中点的方法改进 mid (left right) / 2 //但是如果left和right的数很大&#xff0c;相加会造成内容溢出 改进为 mid left (right - left) / 2 //(right - left)得到整个的长度&…

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

归并排序不使用递归 使用一个变量&#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; …