排序算法复杂度
1、二叉树的按层打印
层序遍历 + 双端队列:
算法流程:
特例处理: 当树的根节点为空,则直接返回空列表 [] ;
初始化: 打印结果空列表 res ,包含根节点的双端队列 queue;
BFS 循环: 当 queue 为空时跳出;
新建列表 temp ,用于临时存储当前层打印结果;
当前层打印循环: 循环次数为当前层节点数(即 queue长度);
出队: 队首元素出队,记为 node;
打印: 若为奇数层,将 node.val 添加至 temp 尾部;否则,添加至 temp 头部;
添加子节点: 若 node 的左(右)子节点不为空,则加入 queue;
将当前层结果 temp 转化为 list 并添加入 res ;
返回值: 返回打印结果列表 res 即可;
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
ArrayList<List<Integer>> res = new ArrayList(); //用来存储最终结果
Queue<TreeNode> queue = new LinkedList<>(); //BFS通常借助队列实现
if(root == null) return res; //判空
queue.add(root);
while(!queue.isEmpty()){
LinkedList<Integer> temp = new LinkedList(); //临时存储节点
for(int i = queue.size(); i > 0; i--) {
TreeNode node = queue.poll();
//先将根节点的值弹出,再检索左节点和右节点
if(res.size() % 2 != 0){
temp.addFirst(node.val); //奇数层->队列头部
}else{
temp.addLast(node.val); //偶数层->队列尾部
}
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
res.add(temp);
}
return res;
}
}
2、字符串拼接
String.substring(beginIndex,endIndex):
从beginIndex开始取,到endIndex结束,其中不包括endIndex位置的字符
3、List转int[]
List.stream().mapToInt(Integer::valueOf).toArray()
4、递推问题
5、摩尔投票法
算法流程:
- 初始化: 票数统计 votes = 0 , 众数 x;
- 循环: 遍历数组 nums 中的每个数字 num ; 当 票数 votes 等于 0 ,则假设当前数字 num 是众 数; 当 num = x 时,票数 votes 自增 1 ;当 num != x 时,票数 votes 自减 1 ;
- 返回值: 返回 x 即可;
// 摩尔投票法
int votes = 0;
int x = 0;
for(int num:nums){
if(votes == 0) x = num;
if(num == x)votes ++; else votes --;
}
return x;
6、快速排序
7、滑动窗口
模板:
public int[][] findContinuousSequence(int target) {
//思路:滑动窗口
//右指针右移-->判断是否需要收缩-->左指针右移-->res
int left = 1,right = 2,sum = 3;
List<int[]> res = new ArrayList<>();
while(left < right){
if(sum == target){
int[] temp = new int[right-left+1];
for(int i=left;i<=right;i++){
temp[i-left] = i;
}
res.add(temp);
}
if(sum < target){
right++; //右指针右移 再加上新的右指针
sum += right;
}else{
sum -= left; //先减去左指针 再将左指针右移
left++;
}
}
return res.toArray(new int[0][]);
}
8、位运算
设有二进制数n,求n中1的个数:
思路1:
-
核心思路:n & (n - 1) 会把n中的最后一个1变成0
-
循环中每次去除n的最后一个1,res记录循环次数,就是1的个数
public class Solution { // you need to treat n as an unsigned value public int hammingWeight(int n) { int res = 0; while(n != 0){ n &= n - 1; res++; } return res; } }
思路2:
-
根据 与运算 定义,设二进制数字 n,则有:
若 n & 1 = 0,则 n 二进制 最右一位 为 0 ; 若 n & 1 = 1,则 n 二进制 最右一位 为 1 。
-
根据以上特点,考虑以下 循环判断 :
判断 n 最右一位是否为 1,根据结果计数。 将 n 右移一位(本题要求把数字 n 看作无符号数,因此使用 无符号右移 操作)。
public class Solution { public int hammingWeight(int n) { int res = 0; while(n != 0) { res += n & 1; n >>>= 1; } return res; } }
9、合并链表
引入伪头节点: 由于初始状态合并链表中无节点,因此循环第一轮时无法将节点添加到合并链表中。
解决方案:初始化一个辅助节点 dum作为合并链表的伪头节点,将各节点添加至 dum之后。
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null || l2 == null) return l1 == null ? l2:l1; //判空
ListNode dum = new ListNode(0),cur = dum; //初始化
while(l1 != null && l2 != null){
//根据 l1.val和 l2.val的大小关系确定节点添加顺序,两节点指针交替前进,直至遍历完毕。
if(l1.val < l2.val){
cur.next = l1;
l1 = l1.next;
}else{
cur.next = l2;
l2 = l2.next;
}
cur = cur.next;
}
//跳出时有两种情况,即 l1为空或 l2为空。
cur.next = l1 != null ? l1 : l2;
return dum.next;
}
}
10、反转链表
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null,cur = head;
ListNode temp = new ListNode(0);
while(cur != null){
temp = cur.next; //暂存后继节点
cur.next = pre; //更改指向
pre = cur; //更新pre
cur = temp; //访问下一节点
}
return pre;
}
}