【常见时间复杂度】
O(1),O(log N),O(N),O(Nlog N),O(N*N),O(M+N),
【常见空间复杂度】
O(1),O(log N),O(N),O(Nlog N),O(N*N),O(M+N),
- 变量
- 递归(递归栈)
【数据结构】【数组】
定义及特点:
在连续的内存空间中,存储一组相同类型的元素,索引从0开始,表示相对位置,
适合读,不适合写===>读多写少
时间复杂度 | ||
访问(Access) | 索引===>元素 | O(1) |
搜索(Search) | 元素===>索引 | O(N) |
插入(Insert) | O(N) | |
删除(Delete) | O(N) |
【力扣485】
/**
* @author 鼠鼠捏~~
* @version 1.0~~
* LeetCode 485 最大连续1的个数
* 思路:
* 两个变量 :
* count 用于存储中间结果
* result 用于存储最后结果
* 遍历数组,
* 若该元素值为1,count++,
* 否则 result = max(result,count),(当前结果与之前结果比较,最大值存入result),并清空count,重新开始记录1的个数
* 遍历完成后返回max(result,count)(最后一次结果与之前结果比较)
*
*/
public class Exer1LC485 {
public int Ex485(int[] arr){
if (arr == null || arr.length == 0){
return 0;
}
int count = 0;//中间值
int result = 0;//结果值
for(int i = 0;i < arr.length;i ++){
if (arr[i] == 1){
//出现 1 count++
count++;
}else {
//出现 0 count与result比较 最大值存入result count清空
result = count > result ? count:result;
count = 0;
}
}
result = count > result ? count:result;
return result;
}
}
【数据结构】【链表】
【数据结构】【队列】
【数据结构】【栈】
定义及特点:
先进后出,浏览器后退功能
时间复杂度 | ||
访问(Access) | 栈顶元素 | O(1) |
搜索(Search) | O(N) | |
插入(Insert) | O(1) | |
删除(Delete) | O(1) |
【力扣20】
/**
* @author 鼠鼠捏~~
* @version 1.0~~
* 要求:
* 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
* <p>
* 有效字符串需满足:
* <p>
* 左括号必须用相同类型的右括号闭合。
* 左括号必须以正确的顺序闭合。
* 每个右括号都有一个对应的相同类型的左括号。
* <p>
* 思路:
* 遍历字符串s,
* 若为左括号:直接入栈
* 若为右括号:
* 1.若此时栈空,return false
* 2.栈非空,判断当前元素是否匹配栈顶元素,返回则出栈
* 遍历结束后,判断栈是否为空,为空返回true;
* isMatch函数用于判断是否匹配
*/
class Solution {
public static boolean isValid(String s) {
Stack<Object> stack = new Stack<>();
//遍历字符串s
for(int i = 0;i < s.length();i ++){
char c = s.charAt(i);
if (c =='('||c=='['||c=='{' ){
//c 为左括号,入栈
stack.push(c);
}else {
//c 为右括号,判断栈是否为空
if (stack.isEmpty()){
return false;
}else {
if (isMatch((char)stack.peek(),c)){
if (!stack.isEmpty()){
stack.pop();
}
}else {
return false;
}
}
}
}
return stack.isEmpty();
}
public static boolean isMatch(char c1 ,char c2){
if (c1 == '(' && c2 ==')'){
return true;
}else if (c1 == '[' && c2==']'){
return true;
}else if (c1 == '{' && c2 =='}'){
return true;
}else {
return false;
}
}
}
【力扣496】
/**
* @author 鼠鼠捏~~
* @version 1.0~~
* 要求:
* nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
* <p>
* 给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
* <p>
* 对于每个 0 <= i < nums1.length ,
* 找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。
* 如果不存在下一个更大元素,那么本次查询的答案是 -1 。
* <p>
* 返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。
* 思路:
* 两个栈stack temp
* stack从上至下为倒序,temp从上至下为正序
* nums2压入左栈stack
* 对于int num = nums1[i],
* 先遍历stack,压入右栈temp,直至找到num,此时判断temp.top 与 num的关系
* top > num:nums1[i]==top,ttop压入左栈
* top < num:ttop压入左栈,继续循环判断temp.top 与 num的关系,直至temp空
* 结束后,若temp为空切nums[i]改变过,nums1[i]==-1,
* 最后,temp全部元素压入左栈,恢复数据
*/
class Solution {
public static int[] nextGreaterElement(int[] nums1, int[] nums2) {
Stack<Integer> stack = new Stack<>();
Stack<Integer> temp = new Stack<>();
//nums2压入stack
for (int i = 0; i < nums2.length; i++) {
stack.push(nums2[i]);
}
for (int i = 0; i < nums1.length; i++) {
int num= nums1[i];
//遍历stack,直至找到num,遍历元素压入temp
while (!stack.isEmpty()) {
if (stack.peek() != nums1[i]) {
temp.push(stack.pop());
}else {
break;
}
}
//判断temp.top num
while (!temp.isEmpty()) {
if (temp.peek() < nums1[i]) {
//ttop < num 压入stack
stack.push(temp.pop());
} else if (temp.peek() > nums1[i]) {
//ttop > num 修改num
//同时ttop压入stack
nums1[i] = temp.peek();
stack.push(temp.pop());
break;
}
}
if (temp.isEmpty() && num == nums1[i]) {
//遍历temp 未找到,num = -1
nums1[i] = -1;
}
while (!temp.isEmpty()) {
stack.push(temp.pop());
}
}
return nums1;
}
}
/**
* 思路二:
* nums2存入stack不变
*
* 遍历stack,寻找nums1[i],并修改max
* max存储nums1[i]右侧比nums1[i]大的数,每次>,均需修改max
* isfound == false用于控制是否找到nums1[i]
* stop<nums1[i],stop压入temp,
* stop>nums1[i],max = stop,stop压入temp
* stop=nums1[i],isfound = true,找到了,结束循环
* nums1[i] = max
* 恢复数据
*/
class Solution2 {
public static int[] nextGreaterElement(int[] nums1, int[] nums2) {
Stack<Integer> stack = new Stack<>();
Stack<Integer> temp = new Stack<>();
//nums2压入stack
for (int i = 0; i < nums2.length; i++) {
stack.push(nums2[i]);
}
for(int i = 0;i < nums1.length;i ++){
int max = -1;//存储nums1[i]右侧比nums1[i]大的数,每次>,均需修改max
boolean isFound = false;//标识是否找到nums1[i]
while (!isFound){
if (stack.peek() < nums1[i]){
//小于,stop压入temp,暂存
temp.push(stack.pop());
}else if (stack.peek() > nums1[i]){
//大于,修改max,stop不知是否是右侧第一个压入temp,暂存
max = stack.peek();
temp.push(stack.pop());
}else if (stack.peek() == nums1[i]){
isFound = true;
}
}
//恢复数据
while (!temp.isEmpty()){
stack.push(temp.pop());
}
nums1[i] = max;
}
return nums1;
}
}
【数据结构】【哈希表】
定义及特点:
又称散列表,以键值对形式存放数据
时间复杂度 | |
访问(Access) | |
搜索(Search),考虑碰撞 | O(1) |
插入(Insert),考虑碰撞 | O(1) |
删除(Delete),考虑碰撞 | O(1) |
碰撞 | O (K) |
public class CommonOperate {
public static void main(String[] args) {
//创建哈希表
//1.数组创建哈希表,数组元素的索引作为key,数组元素的值作为value
String [] hashTable = new String[4];
//2.Java自带创建哈希表
HashMap<Integer, String> map = new HashMap<>();
//添加元素,O(1)
hashTable[1] = "韩梅梅";
hashTable[2] = "李华";
map.put(1,"韩梅梅");
map.put(2,"李华");
//更新元素,O(1)
hashTable[1]= "bishi";
map.put(1,"bishi");//多次put,直接覆盖
//删除元素,O(1)
hashTable[1] = " ";
map.remove(1);
//获取key的值,O(1)
String temp = hashTable[3];
map.get(3);
//检查key是否存在,O(1)
map.containsKey(4);
//哈希表长度,O(1)
map.size();
//哈希表是否为空,O(1)
map.isEmpty();
}
}
【LC217】
/**
* LC217:
*
* 要求:
* 给你一个整数数组 nums 。
* 如果任一值在数组中出现 至少两次 ,返回 true ;
* 如果数组中每个元素互不相同,返回 false 。
*
* 思路:
* nums存入哈希表,检查前后长度是否一致
*/
class Solution {
public static boolean containsDuplicate(int[] nums) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
for(int i = 0;i < nums.length;i ++){
hashMap.put(nums[i],nums[i]);
}
System.out.println(hashMap.toString());
return !(hashMap.size()== nums.length);
}
}
【LC705】
/**
* LC 705 设计一个哈希集合
*
* 要求:
* 不使用任何内建的哈希表库设计一个哈希集合(HashSet)。
*
* 实现 MyHashSet 类:
*
* void add(key) 向哈希集合中插入值 key 。
* bool contains(key) 返回哈希集合中是否存在这个值 key 。
* void remove(key) 将给定值 key 从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。
* 0 <= key <= 10^6
* 最多调用 10^4 次 add、remove 和 contains
*
*
* 思路:
* 创建一个大小为10^6的boolean数组
* true false代表哈希集合中是否有该key
*/
class MyHashSet {
boolean[] hashSet = new boolean[1000001];
public MyHashSet() {
}
public void add(int key) {
hashSet[key] = true;
}
public void remove(int key) {
hashSet[key] = false;
}
public boolean contains(int key) {
return hashSet[key];
}
}
【数据结构】【树】
定义及特点:
“父子关系”,包含根节点,叶子节点,计算高度,从0开始,由下到上,计算深度,从0开始,由上到下,计算层数,从1开始,由上到下
二叉树
分类
- 普通二叉树:每个节点最多两个“孩子”
- 满二叉树:除叶子节点外,每个节点都有两个“孩子”,所有叶子节点在同一层
- 完全二叉树:从树的根节点,从上到下,从左到右,依次填满节点
满二叉树不等同于完全二叉树,满二叉树是完全二叉树,反之不成立
遍历
- 前序遍历:根节点==>左子树==>右子树
- 中序遍历:左子树==>根节点==>右子树
- 后序遍历:左子树==>右子树==>根节点
【LC144】
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
preorder(root, res);
return res;
}
public void preorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
res.add(root.val);
preorder(root.left, res);
preorder(root.right, res);
}
}
【LC94】
/**
* LC 144 二叉树的中序遍历
* 前序遍历:左子树 ==> 根节点 == >右子树
* <p>
* 要求:
* 给你二叉树的根节点 root ,返回它节点值的 中序 遍历。
* <p>
* 思路:
*
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
inorder(root, res);
return res;
}
public void inorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
inorder(root.left, res);
res.add(root.val);
inorder(root.right, res);
}
}
【LC145】
/**
* LC 144 二叉树的后序遍历
* 前序遍历:左子树 ==> 右子树 == >根节点
* <p>
* 要求:
* 给你二叉树的根节点 root ,返回它节点值的 后序 遍历。
* <p>
* 思路:
*
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
postorder(root, res);
return res;
}
public void postorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
postorder(root.left, res);
postorder(root.right, res);
res.add(root.val);
}
}
【数据结构】【堆】
定义及特点:
完全二叉树,堆中每一个节点的值均 大于等于其孩子节点(最大堆)或小于等于其孩子节点(最小堆)
时间复杂度 | |
访问(Access) | |
搜索(Search) | O(1),堆顶元素 |
插入(Insert) | O(log N) |
删除(Delete) | O(log N),堆顶元素 |
【数据结构】【图】
定义及特点:
“朋友关系”,顶点,“邻居节点”,边,度,
分类:有向图,无向图,权重图
入度:多少边指向该顶点
出度:多少边以这个点为起点指向别的顶点
权重图求最短路径:
- 贝尔曼-福特算
- 迪克斯特拉算法