时间复杂度

Java数据结构漫谈-LinkedList

て烟熏妆下的殇ゞ 提交于 2020-02-15 16:10:17
同样是List的数据结构,LinkedList是使用了前后指针,指明节点的方式来表示链表的,这与之前介绍的ArrayList http://www.cnblogs.com/yakovchang/p/java_arraylist.html 中使用数组的方式是截然不同的。LinkedList中的存储节点被称作节点(Node),一个节点的定义如下所示: private static class Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } } 这是LinkedList的一个内部类,不需要使用LinkedList的程序员关心。 LinkedList正是通过next,prev这两个指针来串联起整个List的。 注意:Node节点在初始化的时候同时指明了初始化的节点的前后节点是什么,所以在之后的代码中,往往没有明显的写明新的节点的前后指针指向了哪里。 在LinkedList本身中仅仅记录了List的开始和结束节点,当然,也记录了size: transient int size = 0; transient Node<E> first;

kmp算法总结

安稳与你 提交于 2020-02-15 05:44:12
转载分享,是我看到的最好懂的kmp讲解了!!谢谢原作,贴上链接 原作链接 KMP算法 KMP算法是一种线性时间复杂度的字符串匹配算法,它是对BF(Brute-Force,最基本的字符串匹配算法)的改进。对于给定的原始串S和模式串T,需要从字符串S中找到字符串T出现的位置的索引。KMP算法由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为Knuth–Morris–Pratt算法,简称KMP算法。在讲解KMP算法之前,有必要对它的前身–BF算法有所了解,因此首先将介绍最朴素的BF算法。 一:BF算法简介 如上图所示,原始串S=abcabcabdabba,模式串为abcabd。(下标从0开始)从s[0]开始依次比较S[i] 和T[i]是否相等,直到T[5]时发现不相等,这时候说明发生了失配,在BF算法中,发生失配时,T必须回溯到最开始,S下标+1,然后继续匹配,如下图所示: 这次立即发生了失配,所以继续回溯,直到S开始下表增加到3,匹配成功。 容易得到,BF算法的时间复杂度是O(n*m)的,其中n为原始串的长度,m为模式串的长度。BF的代码实现也非常简单直观,这里不给出,因为下一个介绍的KMP算法是BF算法的改进,其时间复杂度为线性O(n+m),算法实现也不比BF算法难多少。 二:KMP算法 前面提到了朴素匹配算法,它的优点就是简单明了

215. 数组中的第K个最大元素

自闭症网瘾萝莉.ら 提交于 2020-02-15 04:48:19
215. 数组中的第K个最大元素 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 示例 1: 示例 2: 说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。 2.方法一(快速排序) 利用快速排序的思想,对数组进行递减排序,把第k大的元素放到正确的位置。 算法过程: 1.利用partition()随机获取一个元素的下标index。 2.如果index > k-1,说明第k大元素在index的左边,right = index - 1。 2.如果index < k-1,说明第k大元素在index的右边,left = index + 1。 3.当index == k-1,退出循环,返回nums[index]。 3.代码 class Solution { public : int findKthLargest ( vector < int > & nums , int k ) { int left = 0 ; int right = nums . size ( ) - 1 ; int index = partition ( nums , left , right ) ; while ( index != k - 1 ) { if ( index > k - 1 ) { right = index

【算法】算法的时间复杂度和空间复杂度

怎甘沉沦 提交于 2020-02-13 22:27:10
目录结构: contents structure [-] 时间复杂度的定义 推导大O阶 最优、平均、最差时间复杂度 算法的时间复杂度就是估计一个算法所需的时间,算法的空间复杂度就是估计一个算法所需的内存。算法可以以空间换取时间,也可以以时间换空间。比如,需要求出当前年份是否为闰年,可以写个算法进行计算;也可以预先就把近100年的闰年情况加载到内存中,如果是闰年则为1否则为0,这就是以空间换取时间的栗子。通常情况下“复杂度”都是指的是“时间复杂度”,因此在这篇文章中,笔者也重点介绍时间复杂度。 1.时间复杂度的定义 时间复杂度:在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记做T(n)=O(f(n)),它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称为算法的渐进时间复杂度,简称为时间复杂度。可以将算法的时间复杂度理解循环次数。 利用大写O()来体现算法时间复杂度的计法,称为大O计法。 最优算法:一般情况下,随着输入规模n的增大,T(n)增长最慢的算法为最优。 2.推导大O阶 推导的一般步骤: 用常数1取代运算中的所有加法常数 在修改后的运行次数中,只保留最高项 如果最高项阶存在且不为1,则去除与这个项相乘的参数 接下来举几个栗子: #include

数组(Array)——数组介绍

Deadly 提交于 2020-02-13 03:36:03
Arrays(数组) 数组是一个固定长度的存储相同数据类型的数据结构,数组中的元素被存储在一段连续的内存空间中。它是最简单的数据结构之一,大多数现代编程语言都内置数组支持。 为何使用数组存储一堆变量 与单独为每一个元素声明一个变量名相比,我们可以使用数组的索引值访问数组中的每一个元素。 例如:我们需要实现一个系统来存储办公室所有员工的年龄,传统的存储方式如下: 我们为办公室的每一个员工创建一个变量。假设办公室由三个员工,只需声明三个变量:empl_age,emp2_age和emp3_age. 当我们新招募员工进来时,我们需要创建更多的变量来存储员工的年龄。维护这样的系统非常麻烦,每添加一个新的员工,我们就需要修改这个系统的代码。 要人工计算超过20个员工的平均年龄,逐一访问每一个变量让人头痛的。 数组数据结构的出现尝试解决这种问题。数组的特性之一就是,以一个名称保存多个相同数据类型的数据。 在这个例子中,我们可以声明一个名为employees_ages的整型数组来保存所有员工的年龄。 数组的第二个特性就是,数组中的每一个数据元素被存储在一段连续的内存空间中,我们可以以索引的方式访问数组的数据元素。 通过遍历数组的索引来访问每个员工的年龄,使得计算员工年龄的平均值变得更加容易;因为在遍历过程中,数组的名称是恒定的,只有索引在变化。 声明一个一维数组 在使用一个数组之前

算法分析

笑着哭i 提交于 2020-02-12 23:26:40
理解算法分析之前,先看一看科学家的平时如何分析一个问题。 科学方法 1.细致的观察真实世界的特点,通常还需要精确的测量。 2.根据观察结果提出假设模型。 3.根据模型预测未来的事件。 4.继续观察并核实预测的准确性。 5.一直反复直到确认预测和观察一致。 一 观察 陈程序的观察基本就是观察时间的运行,现有一个简单类用于查看时间。 public class Stopwatch { private final long start; public Stopwatch() { start = System.currentTimeMillis(); } public double elapsedTime() { long now = System.currentTimeMillis(); return (now - start) / 1000.0; } public void howManyTime(){ System.out.println("时间过了:"+elapsedTime()); } } 二 数学模型 数学模型的分析大概如下: 1.确定输入模型,定义问题的规模。 2.识别内循环。 3.根据内循环中的操作确定成本模型。 4.对于给定的输入,判断这些操作的执行频率,需要使用数学分析。 三 时间复杂度分析 1、时间复杂度 (1)时间频度 一个算法执行所耗费的时间,从理论上是不能算出来的

2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)

非 Y 不嫁゛ 提交于 2020-02-12 12:24:55
Time:2018.4.29 8:30-13:30 Link A 题意 给出总的路程L,普通速度a,喝咖啡速度后b,等咖啡时间t,咖啡有作用时间r,和n个咖啡厅的位置。买咖啡需要等待,喝咖啡时速度提升 问在哪几个咖啡厅买咖啡,走完总路程所花的时间最短。 可以扔掉咖啡,可以用手机预定咖啡。(L<=1e11,a,b<=200,t<=300,r<=1200,n<=5e5) 假如不可以预定怎么做? 分析 Difficult ym:单调队列优化后dp???,留坑 B solved by ym 题意 四人接力跑,现分别给出n个人的第一棒和其他棒的时间,问选择四个人所用时间最小的时间,和对应的人(即方案) (n<=500) 分析 ym:首先直观的n^4暴力枚举,肯定不行,枚举第一棒贪心选取其余的即可 时间复杂度O(nlogn) C 题意 分析 大大大模拟,留坑 D solved by ym&czh 题意 给出n个长度为m的0/1串,0和0或者1和1都是相同,问找出一个字符串使得与其他所有串相同的的最多的最少(n<=1e5,m<=20) 分析 ym:相同的数量尽可能少==不同的数量尽可能多,故可以将每个串看做一个点出发从其BFS找所有没有出现过的点,找一个different最大 为什么different最大的是答案?我们BFS找到的每一个点都是原来的点最小different 时间复杂度:O(k*2

UOJ191 Unknown

不想你离开。 提交于 2020-02-12 11:34:39
Unknown 有一个元素为向量的序列,下标从1开始,初始时为空,现在你需要支持三个操作: 1.在 \(S\) 的末尾添加一个元素 \((x,y)\) 。 2.删除 \(S\) 的末尾元素。 3.询问下标在 \([l,r]\) 区间内的元素中, \((x,y) \times S_i\) 的最大值。 其中 \(\times\) 表示向量的叉积, \((x_1,y_1) \times (x_2,y_2) = x_1y_2-x_2y_1\) 题解 https://www.cnblogs.com/showson/p/5602460.html 使用线段树按下标维护凸包。那么这里有一个问题,如果按照传统的写法,合并一次的复杂度是与O(区间长度)的,这样会导致单次插入/删除的时间复杂度变为O(n),是不能接受的。 注意到与普通的线段树不一样的是,这个只会从后面添加元素,所以一个区间只有被填满了以后才需要询问,进而我们可以只在这个区间被填满了以后再合并,但是单次操作的最坏时间复杂度仍是O(n)。 考虑是什么样的操作使上面的复杂度变成O(n)的呢:在某个较长的区间的右端点附近来回插入删除,每当它满了就会合并一个,删除再插入一个又会满。 于是我们考虑,在这个区间刚满的时候不合并这个区间,而是等到同层的下一个区间也填满的时候再合并这个区间。 这样一旦一个结点花费O(L)的时间合并后,至少O(L

刷题No24. sort-list(排序)(java)【链表】

血红的双手。 提交于 2020-02-11 19:05:44
题目: 在O(n log n)的时间内使用常数级空间复杂度对链表进行排序。 思路: 由于题目要求,时间复杂度要求为O(n log n),所以,需要用归并排序。 找到链表的中间节点 通过中间节点将链表1分为2 两个链表进行比较,比较完之后进行合并。 代码: package com.company; import java.util.List; public class TestNo24 { //定义单链表 static class ListNode{ int val; ListNode next; ListNode(int x){ val = x; next = null; } public String toString(){ if(this.next == null){ return String.valueOf(this.val); } return this.val + "->" + this.next.toString(); } } public static void main(String[] args) { TestNo24 t = new TestNo24(); ListNode head = new ListNode(4); head.next = new ListNode(5); head.next.next= new ListNode(7); head

复杂度

半世苍凉 提交于 2020-02-11 16:01:00
复杂度 复杂度分析 数据结构和算法的目标:快、省,即执行效率和资源消耗 “事后统计法”具有很大局限性,提前预估效率很重要 复杂度分析是学习算法的精髓和分析算法的利器 时间复杂度 假设每行代码执行时间意义,所有代码的执行时间 T(n) 和每行代码的执行次数 n 成正比。 T(n) = O (f(n)) 大O时间复杂度表示代码执行效率随数据规模增长的变化趋势,也叫 渐进时间复杂度 。 当n很大时,低阶、常量、系数并不左右增长趋势,可以省略,只需要记录最大量级。 只关注循环次数最多的一段代码. 加法法则:总复杂度等于量级最大的那一段代码。 乘法法则:嵌套代码的复杂度等于内外代码复杂度之积。 常见复杂度量级 非多项式量级: \(O(2^n),O(n!)\) ,称为NP算法,效率较低。 多项式量级: \(O(1),O(logn),O(n),O(nlogn),O(n^k)\) 。 \(O(1)\) int i = 1 ; int j = 2 ; int sum = i + j ; 常量级时间复杂度的表示方法,即便有 3 行,也是 O(1) ,并非 O(3) 。一般情况下,只要不存在循环、递归,复杂度都为 O(1) ,与代码量无关。 \(O(logn)、O(nlogn)\) int i = 1 ; while ( i <= n ) { i = i * 2 ; } 这段代码的复杂度为 \(O