情况A: 路径经过左子树的最深节点,通过根节点,再到右子树的最深节点。
方案:计算两个节点到根节点的深度相加。
情况B: 路径不穿过根节点,而是左子树或右子树的最大距离路径,取其大者。
方案:计算两个节点到子树根节点的深度相加
利用空间换时间。使用临时变量保存之前计算好的值。
分配饼干问题?每个孩子都有一个满足度,每个饼干都有一个大小,只有饼干的大小大于一个孩子的满足度,该孩子才会获得满足。求解最多可以获得满足的孩子数量。Input:[1,2], [1,2,3]。Output: 2
贪心算法。对饼干、孩子满足度进行排序。然后先用小饼干给满足度低的孩子。不造成浪费。
public static int treeDepth(TreeNode root) { if (root == null) { return 0; } // 计算左子树的深度 int left = treeDepth(root.left); // 计算右子树的深度 int right = treeDepth(root.right); // 树root的深度=路径最长的子树深度 + 1 return left >= right ? (left + 1) : (right + 1); }
借助一个队列和一个栈,方法和打印层遍历类似,区别在于隔层利用栈来逆序遍历。
复制成 1->1'->2->2'->3->3' 的链表,然后再拆分出来 1'->2'->3'
第一种做法:先将链表拆分成奇数的链表,和偶数的链表,然后翻转偶数的链表,在合并两个链表。
不支持随机访问,查找的时间复杂度是O(n)
准备两个指针,一个步长为1,一个步长为2,当遍历到的指针相同时,则判定出现环
最小堆算法
遍历数组,从第一个大于0的数字开始累加,保存最大值,如果累加后的值小于等于0的话,就抛这一下标,
从下一个下标开始累积,如果超过之前的最大值的话就进行替换。使用sum和max变量进行操作
将所有数字放入数字对应下标的数组,有N个相同的数字,该下标的值就为N。
从i下标开始遍历,S-i下标对应值>0的话,就找到组合。 i=s-i的话,做特殊处理。
所有值进行异或运算。最后的值再和0异或,得到原来的值。
先找出旋转90度,下标的变换规律。 然后从外圈向内圈旋转变换。
排序算法 | 时间复杂度 |
---|---|
冒泡排序 | O(n2) |
选择排序 | O(n2) |
插入排序 | O(n2) |
希尔排序 | O(n1.5) |
快速排序 | O(N*logN) |
归并排序 | O(N*logN) |
堆排序 | O(N*logN) |
基数排序 | O(d(n+r)) |
基本思想:(分治)
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。
首先考虑下如何将2个有序数列合并。这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,
取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
PriorityQueue是一个基于优先级堆的无界队列,它的元素是按照自然顺序(natural order)排序的。
在创建的时候,我们可以给它提供一个负责给元素排序的比较器。PriorityQueue不允许null值,因为
他们没有自然顺序,或者说他们没有任何的相关联的比较器。最后,PriorityQueue不是线程安全的,
入队和出队的时间复杂度是O(log(n))。
从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,
进行运算,运算结果进栈,一直到最终获得结果。
对于表达式计算非常方便
重写LinkedHashMap
public class LRUCache<K, V> extends LinkedHashMap<K, V> { private final int MAX_CACHE_SIZE; public LRUCache2(int cacheSize) { super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true); MAX_CACHE_SIZE = cacheSize; } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_CACHE_SIZE; } }
声明一个大小为10000000的数组,每次随机出来的数i,都去数组下标i-1的位置看是否为0,如果为0的话,
写入这个数字,并记录数组的真实大小,等数组的真实大小为10000000的时候,停止随机。
同时遍历两个数组,每次对比两个数组当前坐标的值哪个小,小的存入新的数组,数组下表往后移一位,
大的那边坐标不变,继续下次大小对比。依次循环。
每次交换头尾的值,并坐标向中间靠拢。
前序递归:
public void preOrderTraverse1(TreeNode root) { if (root != null) { System.out.print(root.val + "->"); preOrderTraverse1(root.left); preOrderTraverse1(root.right); } }
前序非递归:
public void preOrderTraverse2(TreeNode root) { Stack<TreeNode> stack = new Stack<>(); TreeNode node = root; while (node != null || !stack.empty()) { if (node != null) { System.out.print(node.val + "->"); stack.push(node); node = node.left; } else { TreeNode tem = stack.pop(); node = tem.right; } } }
中序递归:
public void inOrderTraverse(TreeNode root) { if (root != null) { inOrderTraverse(root.left); System.out.print(root.val + "->"); inOrderTraverse(root.right); } }
中序非递归:
public void inOrderTraverse(TreeNode root) { Stack<TreeNode> stack = new Stack<>(); TreeNode node = root; while (node != null || !stack.isEmpty()) { if (node != null) { stack.push(node); node = node.left; } else { TreeNode tem = stack.pop(); System.out.print(tem.val + "->"); node = tem.right; } } }
后序递归:
public void postOrderTraverse(TreeNode root) { if (root != null) { postOrderTraverse(root.left); postOrderTraverse(root.right); System.out.print(root.val + "->"); } }
后序非递归:
public void postOrderTraverse(TreeNode root) { TreeNode cur, pre = null; Stack<TreeNode> stack = new Stack<>(); stack.push(root); while (!stack.empty()) { cur = stack.peek(); if ((cur.left == null && cur.right == null) || (pre != null && (pre == cur.left || pre == cur.right))) { System.out.print(cur.val + "->"); stack.pop(); pre = cur; } else { if (cur.right != null) stack.push(cur.right); if (cur.left != null) stack.push(cur.left); } } }
层次遍历:
public void levelOrderTraverse(TreeNode root) { if (root == null) { return; } Queue<TreeNode> queue = new LinkedList<TreeNode>(); queue.add(root); while (!queue.isEmpty()) { TreeNode node = queue.poll(); System.out.print(node.val + "->"); if (node.left != null) { queue.add(node.left); } if (node.right != null) { queue.add(node.right); } } }
深度优先算法:利用栈实现
广度优先算法:利用队列来实现
利用栈与后缀表达式利于计算机方便计算
按权重将节点分布在一条右子树上,使得前缀不重复
利用bit数组,通过不同的哈希函数定位数组中的坐标。 如果都存在的话,代表存在。有一定误判率。
数组查找是O(1),删除或者新增是O(N) 链表查找是O(N),删除或者新增是O(1)
递归遍历和循环遍历
MD5和SHA256
1.保护密码。
2.防止文件篡改
3.数字签名(对整段内容加密比较费性能,所以只对哈希值进行加密)
4.文件秒传
可以使用类似选择排序,类似快排,类似最大堆的算法
利用原子数字,对三取余,打印对应的abc。或者利用三个condition进行唤醒。
分治,加最小堆
1b是8比特。 1kb是8192比特 大概12mb内存可以代表1亿数字的比特位 利用哈希来判断
准备一个大数组。依次放入数组。数字出现n次,对应下标值就为n,完成之后,遍历数组。
当累加数值为1亿时,对应下标即为中位数。时间复杂度即为O(N)
累加每个位置上的bit位%3 即为不重复的数字的bit位
在原数组中对调首尾对称的位置
log2N 优势是 性能平均
递归更换左右子树即可
准备两个指针,初始指向头结点, 1号指针先走n步,然后2号指针开始走,当1号指针走到尾节点时,2号指针即为倒数第N个数据。
依次遍历每个有序数组(假设数组从大到小),对比这200个数字,最大的放入top20数组,重复20次该操作,即可获得top20数组
一个步长为1的游标,一个步长为2的游标,当步长为2的游标到达链表末尾时,步长为1的游标即中间元素
分割,或者流式读取,然后利用一个大小为10的小根堆。 或者分成100份,每份计算最大的10个数字,最后对比这个1000个数字
有几台机器存储着几亿淘宝搜索日志,你只有一台2g的电脑,怎么选出搜索热度最高的十个搜索关键词?
先划分成多个小文件,送进内存排序,然后再采用多路归并排序。
快排等算法。
先用遍历一次十万单词,放入hashmap中,key为单词,value为次数。然后再遍历hashmap,放入最小堆,可以使用priorityqueue或者大小为10的数组也行