【学习笔记】在刷题前--数据结构和操作

数据结构和操作

复杂度

1.算法的时间复杂度

大O表示法,常数的就不要了,主要是去看循环,看循环体循环了多少次。其实就是主要去关注控制循环结束的条件,for里对应很多的n,n^2; while里循环条件如果有涉及到了循环体,有很多是logN;

2.算法的空间复杂度

主要去关注变量,尤其是数组;然后去关注递归;

数据结构

1.数组Array

连续的; 相同类型的; -> 读多写少;

1.1 复杂度

访问 access:根据索引找元素:O(1);
搜索 search:在整个数组里去找元素:O(N);
插入 insert:O(N);
删除 delete:O(N);

1.2 java中数组常用操作
//创建数组的两种方法: int[] array = new int[3]; //知道数组长度; ArrayList<Integer> array = new ArrayList<>(); //不知道要创建的数组长度; -------------------------------------- //ArrayList中的方法: 插入: array.add(4); //在尾端插入4; array.add(3,4); //在索引3处插入4; 访问: array.get(3); //访问索引为3的元素; 更新: array.set(3,4); //更新索引3处的元素为4; 删除: array.remove(3); //删除元素3; 长度: array.size(); //注意不是第一种方式的length; 查找: array.contains(4); 转数组:array.toArray(new int[n]); //括号里写具体的数组类型,不然都转成object了; List<Integer>转int[]: int[] arr = list.stream().mapToInt(Integer::valueOf).toArray(); -------------------------------------- //此外在数组中常用到排序等,可以直接调用Arrays类; Arrays类常用方法: Arrays.sort(nums); //对数组nums按照升序排序;复杂度:O(NlogN); Arrays.toString(nums); //将数组内容转化为字符串; Arrays.asList(nums[1],nums[2],nums[3]); //将数组转化为List集合。使用对象类型数组。 //注意此方法得到的list数组的长度是不可变的。也就是不能删除或添加了。 Array.binarySearch(); //二分搜索指定元素下标(找到返回下边, //找不到返回一个负数,取反~后是该放在的位置,注意一定需要是排序好的数组。只要用二分法必须排序好) Arrays.copyOf(arr,3); //截取arr数组的前3个数据,3指的是长度,如果大于数组长度,则补0; Arrays.fill(arr, ‘a’); //将数组全填为a; Collections类常用方法: Collections.reverse(list); //直接对列表中元素反转;
1.3 python中数组常用操作
a = [] # 创建数组 a.append(1) #在末尾添加; a.insert(2,1) #在索引2添加元素1; a[2] #访问元素; a[2] = 2 #更新元素; a.remove(4) #删除4这个元素; a.pop(1) #删除1索引的元素;不指定默认是最后 a.pop() #删除最后一个元素; del a[4] #删除索引4的元素; size = len(a) #获取a的长度; index = a.index(2) #获取元素2的索引; a.sort() #升序; a.sort(reverse = True) #降序; a[::-1] #数组反转 -------------------------------------- for i in a: # 遍历数组的三种方法,尽量用1,2,避免出现下标 print(i) for index, element in enumerate(a): print("index at ",index, "is :",element) for i in range(0, len(a)): print("i:" , i, "element : ", a[i])
1.4 常见注意
  • 1、数组中经常有一类题型:往往和字符串结合起来比如找出某某子数组或者子串,其和为多少等等,这时候常用前缀和去解,即 连续子数组+和 --> 前缀和;连续子串+最值 --> 滑动窗口
  • 2、如果看到要在有序数组中找某个值,那就用二分查找去解,即有序数组+搜索 --> 二分查找

2.链表Linked List

不连续的; 相同类型的; -> 写多读少;

2.1 复杂度

访问 access:根据索引找元素:O(N);
搜索 search:在整个数组里去找元素:O(N);
插入 insert:O(1);
删除 delete:O(1);

2.2 java中链表常用操作
//创建链表 LinkedList<Integer> list = new LinkedList<>(); -------------------------------------- //LinkedList中的方法 添加:list.add(3); //在末尾插入元素3; list.add(2,3); //在2的位置插入元素3; list.addLast(3); //在末尾插入元素3,可以把链表作为栈或者队列; 访问:list.get(2); //得到索引2的元素; 搜索:list.indexOf(3); //找到元素3的索引; 更新:list.set(2,3); //更新索引2的元素为3; 删除:list.remove(2); //删除索引为2的元素; 长度:list.size(); //链表的长度;
2.3 python中链表常用操作
linkedlist = deque() #创建链表; linkedlist.append(1) #末尾添加元素1linkedlist.insert(2,1) #在索引2位置添加元素1element = linkedlist[2] # 访问索引2的元素; index = linkedlist.index(2) #获取元素2的索引; linkedlist.remove(4) #删除4这个元素; del linkedlist[4] #删除索引4的元素; size = len(linkedlist) #获取a的长度;

3.队列Queue/Deque

排队 -> 先到先得,先进先出

3.1 复杂度

访问 access:根据索引找元素:O(N);
搜索 search:在整个数组里去找元素:O(N);
插入 insert:O(1);
删除 delete:O(1);

3.2 java中队列常见操作
//创建队列 Queue<Integer> queue = new LinkedList<>(); -------------------------------------- //队列的方法 添加:queue.add(3); queue.offer(3) //在队尾添加元素3;offer要更优一些; 获取即将出队的元素:temp = queue.peek(); //获取出队的元素; 删除即将出队的元素:temp = queue.poll(); 判断是否为空:queue.isEmpty(); 队列长度:queue.size(); -------------------------------------- //双端队列:相当于集成了队列和栈;能够先入先出,也能后后入先出; Deque<Integer> deque = new LinkedList<>(); //创建一个双端队列; deque.pollLast(); //移除队尾元素; deque.pollFirst(); //移除队首元素; deque.peekFirst(); //队首元素; deque.peekLast(); //队尾元素;
3.3 python中队列常用操作
from Collections import deque queue = deque() #创建双端队列; queue.append(2) #添加元素; temp1 = queue[0] #获取即将出队的元素; temp2 = queue[-1] #获取队尾元素 temp2 = queue.pop() #删除队尾元素; temp2 = queue.popleft() #删除出队的元素; len(queue) == 0 # 判断队列是否为空; -------------------------------------- while len(queue) > 0: #遍历队列 temp = queue.popleft() print(temp)

4.栈stack

箱子 -> 先进后出

4.1 复杂度

访问 access:只访问栈顶:O(1);
搜索 search:在整个数组里去找元素:O(N);
插入 insert:O(1);
删除 delete:O(1);

4.2 java中栈常用操作
//创建栈 Stack<Integer> stack = new Stack<>(); -------------------------------------- //栈方法 添加:stack.push(3); //在栈顶添加元素3; 获取栈顶元素:stack.peek(); 删除栈顶元素:stack.pop(); 栈的大小:stack.size(); 是否为空:stack.isEmpty();
4.3 python中栈常见操作
stack = [] # 创建栈; stack.append(1) #添加元素; stack[-1] #获取栈顶元素 temp = stack.pop() #删除栈顶元素; -------------------------------------- while len(stack) > 0: #遍历队列 temp = stack.pop() print(temp)
4.4 栈的常见注意

1、栈往往会用来解决那种两两匹配,两两抵消消消乐的问题,比如常见的有效括号等,就是判断后入栈的相邻元素是否有相互关系能够相互抵消,

5.哈希表HashTable

键值对 key-value

5.1 复杂度

访问 access:无;
搜索 search:O(1); 如果碰撞:O(K) K为碰撞的个数
插入 insert:O(1);
删除 delete:O(1);

5.2 java中哈希表常用操作
//创建哈希表 ①、String[] hashTable = new String[4]; //通过数组创建,因为数组的index默认作为了key; ②、HashMap<Integer, String> map = new HashMap<>(); -------------------------------------- //哈希表方法 添加:map.put(1, "lihua"); 更新:map.put(1, "liming"); 删除:map.remove(1); 获取:map.get(3); 获取键值:map.keySet(); //是个数组; 获取值: map.values(); //是个数组; 检查key存在:map.containsKey(3); 长度:map.size(); 是否为空:map.isEmpty(); 有key:是key对应的value,没key:默认值;map.getOrDefault(key,default); map.put(key, val); //没key,添加;有key,会覆盖原来的; map.getOrDefault(key, default); //有key,得到其value; 没key,得到default值; map.putIfAbsent(key, val); //if存在key,那就不会放入,不存在的时候再存; //遍历哈希表: for(Map.Entry<String, Integer> entry : map.entrySet()){ entry.getKey(); entry.getValue(); //得到key和value; }
5.3 python中哈希表常用操作
hashtable = [] #通过数组创建,key即为数组下标; hashtable[2] = "liming" #添加元素/修改元素 ---------------------------------------------- mapping = {} #通过字典创建; # 这样的时候if有key1不在哈希表里直接mapping[key1]会报错 from collections import defaultdict mapping1 = defaultdict(int) #参数是一个函数,可以是int,str,float,list等,意思就是每个元素会默认的是当前的类型的默认值 # 比如现在就是默认的是0, list就会默认的是[] # 另外,Counter这个函数对可迭代对象统计个数后,返回也是一个字典,并且这个字典if有元素不在,然后直接count1[a],这样不会有错。 mapping["key1"] = "liming" #添加元素/修改元素; mapping.get(key, default = None) # 第二个参数在key不存在时可以指定一个返回值;例如 mapping.get(key, []) key不存在的时候会返回一个空列表 # 其次注意字典的key只能是不可变对象; mapping.pop("key1") #删除元素 “key” in mapping #检查key是否存在; mapping.values() #得到value值组成的列表 mapping.keys() #key值组成的列表 mapping.items() #仍然是列表,列表里存放的是元祖,(key, value) # 在python3.6之后,dict是按照添加元素的顺序进行返回的; # if想要dict是有序的,可以用OrderedDict from collections import OrderedDict dict1 = OrderedDict() # 则是按照元素的插入顺序;
5.4 常见注意
  1. 哈希表在刷题的时候常常会用在涉及到次数的问题上,比如某个数字或者某个字符出现了几次;

6.集合Set

无序、不可重复 主要作用:查看重复元素

6.1 复杂度

访问 access:无;
搜索 search:无哈希冲突O(1); 有哈希冲突:O(K)
插入 insert:无哈希冲突O(1);有哈希冲突:O(K)
删除 delete:无哈希冲突O(1);有哈希冲突:O(K)

6.2 java中集合常见操作
//创建hashset HashSet<Integer> set = new HashSet<>(); //hashset方法 添加:set.add(4); //如果Set集合中不包含要添加的对象,则添加对象并返回true;否则返回false。 搜索:set.contains(4); 删除:set.remove(4); 长度:set.size(); 遍历: Iterator it = set.iterator(); while (it.hasNext()) { System.out.print(it.next()); }
6.3 python中集合常见操作
s = set() #创建一个集合 s.add(2) #添加元素2; 2 in s # 搜索2是否在集合s; s.remove(2) #删除元素2;
6.4 常见注意
  1. set在刷题的时候常常会用在涉及到有无重复,独一无二,唯一等问题上,比如某个数字是否重复,是否出现过,用的都是set的不可重复性;

6.树Tree

父子关系

概念
  • 节点:根节点、叶子节点(度为0的节点);
  • 节点的度:一个节点含有的子节点的个数;
  • 树的度:最大的节点的度;
  • 二叉树:每个节点最多有两个孩子;节点的度可以为0,1,2;
  • 满二叉树:除了叶子节点,每个节点都有两个孩子;并且所有叶子节点在一层;
  • 完全二叉树:从上到下,从左到右,依次填满;

满二叉树的概念最小;限制最多,满二叉树一定是完全二叉树

性质

1.完全二叉树除了最后一层外,下一层节点个数是上一层两倍,
如果一颗完全二叉树的节点总数是n,那么叶子节点个数为n/2(n为偶数)或(n+1)/2(n为奇数);

遍历
  • 前序遍历:根节点 -> 左子树 -> 右子树;
  • 中序遍历:左子树 -> 根节点 -> 右子树;
  • 后序遍历:左子树 -> 右子树 -> 根节点;

常用

  1. 二叉树解题的时候往往用到的是递归方法,注意千万不要陷入递归压栈过程中去,就想函数功能,终止条件,一层节点能做什么,什么时候做。
  2. 深度优先(DFS)与广度优先(BFS): DFS与BFS都是用来遍历的手段,在树和图里都是用这两种方法。
    1. DFS:DFS的意思就是比如说一颗树,就先到树的左节点,然后再往树的左节点,一直到最后走不了了,然后回到上一层,去右节点,再回到上一层,如此往复。对于图,就是去往开始节点的一个邻居节点,然后再去此邻居节点的邻居节点,然后到头,返回上一个,如此往复。所以只要用到DFS肯定会用到递归。
    1. BFS:BFS的意思就是比如说一棵树,到左节点,然后到右节点,然后再到左节点的下一层,右节点的下一层,这样子一层一层的往下走,直到最后一层。对于图,去往源点的邻居节点,把源点的邻居节点都走完之后,再去下一个节点,所以BFS就会用到队列的结构,在树里,把节点入队,然后每次出队,就把出队节点的左右孩子入队,这样做到一层一层遍历。在图里,把源点入队,然后把出队点的邻居节点都入队。这样往复。但是在图里为了防止重复访问,需要设置当前节点是否被访问过。(比如可以设置一个vis数组设置为true或false,或者设置一个哈希表这样)
    1. 在树里经常用DFS,在图里经常用BFS(因为树可以很方便的去递归左右子树,而图则对邻居节点比较方便);
    1. 树和图里的BFS区别:
    • 1.树只有一个root,而图可以有多个源点,所有首先需要将多个源点入队。
    • 2.树是有向的因此不需要设置标志是否访问过,而对于无向图而言,必须得标志是否访问过!并且为了防止某个节点多次入队,需要在入队前将其设置为已访问!
    • 3.一个源点的广度优先和多个源点的广度优先:广度优先搜索

7.堆Heap

7.1 概念
  • 前提:完全二叉树
  • 根节点全部≥叶子节点:大根堆:堆顶元素最大;
  • 根节点全部≤叶子节点:小根堆:堆顶元素最小;
7.2 复杂度

访问 access:无;
搜索 search:查看堆顶元素:O(1);
插入 insert:O(logN):每次添加的元素去和父亲节点做对比;和兄弟节点没有关系;
删除 delete:O(logN)

7.3 java中堆常用操作
// 创建堆 PriorityQueue<Integer> minheap = new PriorityQueue<>(); //创建小根堆; PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>() { public int compare(Integer num1, Integer num2) { return num2 - num1; } }); //堆的排序指的是从上往下排; //创建大根堆,注意要排序,重写比较器; /**o1-o2为升序序排列,o2-o1为降序排列,若具体到某一字段,则根据该字段进行排列*/ @Override public int compare(Node o1, Node o2) { if (o1.x==o2.x) //若x属性相等,根据y来升序 return o1.y-o2.y; return o1.x-o2.x;//x属性不相等,根据x来升序排列 } ---------------------------------------------- //PriorityQueue方法 添加元素:minheap.add(3); 堆顶元素:minheap.peek(); 删除堆顶元素:minheap.poll(); 堆里元素数量:minheap.size(); 边遍历边删除: while( !minheap.isEmpty() ){ System.out.println(minheap.poll()); }
7.4 python中堆常用操作
import heapq minheap = [] heapq.heapify(minheap) #第一种方法,先创建一个列表,然后堆化;只能创建小根堆 heapq.heapush(minheap, 10) #第二种方法,添加元素; minheap[0] #堆顶元素; heapq.headpop(minheap) #删除堆顶元素; ---------------------------------------------- while len(minheap) != 0: print(heapq.heapop(minheap)) # 创建大根堆的方法:乘以-1 l1 = list(str1) heapq.heapify(l1) #小根堆 newl1 = [(-i,l1[i]) for i in range(len(l1)] heapq.heapify(newl1) #按照第一个元素变为了小根堆,也就是i的大根堆 max_heap = list() while newl: _, s = heapq.heappop(newl) max_heap.append(s)

8.图Graph

邻居关系

概念
  • 顶点;邻居顶点;边;
  • 度(degree):每个顶点有几条边;
  • 无向图;
  • 有向图:
    • 入度:有多少条边指向该顶点;
    • 出度:有多少条边指向别的顶点;
  • 权重图:
    • 求最短路径;
      • 贝尔曼-福特算法;
      • 迪克斯特拉算法;

总结

数组
链表
队列:先入先出;
栈:后入先出;
堆:最大堆;最小堆;
哈希表: key | value;
哈希集合:无序、不可重复;

  • 知道每个结构的特性;
  • 每个结构的增删改查复杂度;

关于排序好的数组;

排序好的数组有以下几种常见的处理方法:

  • 1.二分查找:二分查找的使用前提就是数组必须是有序的,这样才能每次取中间值去逼近;二分查找总结
  • 2.首尾双指针:首尾双指针也常常用在排序数组上,尤其是涉及到两个数之和时,因为如果和大了或者小了可以去移动首或尾指针;

关于历史信息

  • if想要记录历史中的最大值或者最小值,或者是历史中的顺序问题,那总不能再次重新遍历了,往往就会用到优先队列(堆)
    比如大根堆:总是维持了历史中的k个最小的,if来的比顶还大,那就直接走,if来的比堆顶小,那就把最大的(堆顶)弹出去,小的进来,这样不断更新堆,也就维持了k个最小的;

__EOF__

本文作者Curryxin
本文链接https://www.cnblogs.com/Curryxin/p/16084454.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Curryxin  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
Live2D
欢迎阅读『【学习笔记】在刷题前--数据结构和操作』
点击右上角即可分享
微信分享提示