
算法
叕叕666
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
有苦有乐的算法 --- 图的宽度优先遍历
题目 给定一个图,使用队列对其进行宽度优先遍历 代码 public static void bfs(Node start) { if (start == null) { return; } Queue<Node> queue = new LinkedList<>(); HashSet<Node> set = new HashSet<>(); queue.add(start); set.add(start); while (!queue.isE原创 2021-12-09 15:08:41 · 173 阅读 · 0 评论 -
有苦有乐的算法 --- 图的深度优先遍历
题目 给定一个图,使用栈对其进行深度优先遍历 代码 public static void dfs(Node node) { if (node == null) { return; } Stack<Node> stack = new Stack<>(); HashSet<Node> set = new HashSet<>(); stack.add(node); set.add(node); System.out.println(node.val原创 2021-12-09 15:06:34 · 208 阅读 · 0 评论 -
有苦有乐的算法 --- 并查集的实现原理
假如有两个集合: 找出一个节点作为集合的‘头’,集合内的其他节点都与这个‘头’进行关联(可以直接找到这个‘头’); 如果需要在集合A中查找一个元素是否存在,或者判断两个元素是否属于同一集合,只需判断它们的‘头’是否相同即可; 当集合B想要加入集合A时,只需让集合B的头关联集合A 当在集合A中查找7和8是否属于同一集合时,找到最顶级的‘头’,判断是否相同; 找到最顶级的‘头’之后,将经过的节点全部与‘头’关联包括自己; 查找7的‘头’后: 查找8的‘头’后: ...原创 2021-11-29 14:43:06 · 82 阅读 · 0 评论 -
有苦有乐的算法 --- 判断一颗二叉树是否是完全二叉树、是否是平衡二叉树、是否是搜索二叉树
是否是完全二叉树 完全二叉树:二叉树的每一层要么是满的,要么从左到右处在变满的路上。 public static boolean isCBT(Node head) { if (head == null) { return true; } return process(head).isCBT; } public static class Info { public boolean isFull; public boolean isCBT; public int height; public原创 2021-11-18 15:40:14 · 259 阅读 · 0 评论 -
有苦有乐的算法 --- 获取二叉树的最大宽度
题目 一颗二叉树,求其最大宽度。 例: 解析 按层遍历二叉树; 在遍历时,使用用4个变量来记录信息; Node curEnd = null; // 当前层,最右节点是谁 Node nextEnd = null; // 下一层,最右节点是谁 int max = 0; // 暂时最大宽度 int curLevelNodes = 0; // 当前层的节点数 头结点入队,curEnd = 头结点;nextEnd = 头结点的右节点; 头结点出队,curLevelNodes ++,此时 出队节点==curEnd,原创 2021-11-17 17:05:59 · 432 阅读 · 0 评论 -
有苦有乐的算法 --- 二叉树的按层遍历
题目 给定一个二叉树,进行按层遍历。 例: 解析 给定一颗二叉树: 首先准备一个队列,让头节点入队; 节点出队并打印,同时此节点的左节点2入队,右节点3在入队; 2出队,2的左节点4入队,2的右节点5在入队; 3出队,3的右节点6在入队; 最后以此出队,得到结果。 代码 public static class Node { public int value; public Node left; public Node right; public Node(int v) { value原创 2021-11-17 14:49:04 · 217 阅读 · 0 评论 -
有苦有乐的算法 --- 用栈和递归的方式实现二叉树的前序遍历、中序遍历、后序遍历
前序遍历 递归方式: public static void pre(Node head) { if (head == null) { return; } System.out.println(head.value); pre(head.left); pre(head.right); } 栈的方式: public static void pre(Node head) { System.out.print("pre-order: "); if (head != null) { Stack原创 2021-11-17 14:17:57 · 291 阅读 · 0 评论 -
有苦有乐的算法 --- 可能有环也可能无环的两个单链表,判断这两个链表是否相交,如果相交返回相交的第一个节点
题目 可能有环也可能无环的两个单链表,判断这两个链表是否相交,如果相交返回相交的第一个节点。 解析 第一步,判断链表是有环链表还是无环链表; 如果一个单链表无环,它一定有一个指向null的尾结点; 如果一个单链表有环,用两个指针oneStep,twoStep,twoStep一次走两个节点,oneStep一次走一个节点,这两个指针必定会相遇; 此时将twoStep重新遍历,一次走一个节点,oneStep也继续一次走一个节点,二次相遇的时候,这个节点就是入环节点。 第二步,判断是否相交; 2-1:一个单链表有原创 2021-11-15 16:47:56 · 692 阅读 · 0 评论 -
快速排序、归并排序、堆排序的对比,如何选择最优的排序?
快速排序、归并排序、堆排序都是时间复杂度为O(N*logN)的排序,那么该用哪种排序算法呢? 快速排序、归并排序、堆排序空间复杂度的对比: 快速排序 归并排序 堆排序 O(logN) O(N) O(1) 发现,堆排序的堆排序的空间复杂度最低,那么是不是堆排序最好呢? 其实还是要看具体场景的。 如果即需要追求速度,还需要减少空间的使用,那么堆排序是首选的。 快速排序、归并排序、堆排序都是时间复杂度为O(N*logN),但常数时间项快速排序是最低的; 如果只需要追求速度,那么快速排序是首选的原创 2021-11-12 14:06:54 · 1493 阅读 · 0 评论 -
有苦有乐的算法 --- 基数排序
题目 一个无序数组,使用基数排序的方式从小到大进行排序 解析 给定一个数组: 首先准备一个"桶"(每个桶是一个队列); 从左到右遍历数组,每个元素的个位数是多少,就进入几号桶中; 在从左到右遍历桶,桶内元素先进先出依次排列,得到了一个按个位数从小到大排序的数组; 这个数组从左到右遍历数组,每个元素的十位数是多少,就进入几号桶中,在遍历桶依次排列元素,按十位数从小到大排好序的数组; 在按照百位数重复操作,得到了最终排好序的数组; 代码 public static void radixSort(in原创 2021-11-10 20:13:54 · 571 阅读 · 0 评论 -
有苦有乐的算法 --- 计数排序
题目 一个数组,其数据范围在0~200之间,将其从小到大排序 解析 给定一个数组; 首先获取去最大值,然后创建一个长度为这个最大值+1的临时数组; 遍历原数组,如果原数组中的元素是n,在临时数组索引为n的位置加1; 临时数组为: 把元素的索引作为值,元素作为值的个数复制到原数组; 代码 public static void countSort(int[] arr) { if (arr == null || arr.length < 2) { return; } int max =原创 2021-11-08 11:16:01 · 81 阅读 · 0 评论 -
有苦有乐的算法 --- 一个无序数组,如果从小到大排好序,任何一个元素任何一个元素移动索引长度不超过k,实现排序
题目 一个无序数组,如果从小到大排好序,任何一个元素任何一个元素移动索引长度不超过k,实现从小到大排序 例: k=2 排序后,[4]移动2个索引,[6]移动2个索引,[1]移动2个索引,[3]移动2个索引,[7]移动1个索引,[6]移动1个索引 解析 给定一个满足条件的数组,k=2;创建一个 大小为k+1的小根堆,先填满,出一个元素,在入一个元素即可实现排序 代码 public static void sortedArrDistanceLessK(int[] arr, int k) { if (k ==原创 2021-11-02 14:59:44 · 214 阅读 · 0 评论 -
有苦有乐的算法 --- 随机快排
题目 使用随机快排对给定数组进行从小到大排序 [5,3,2,1,5] ⇒ [1,2,3,5,5] 解析 给定一个数组 1.在数组中找出一个数作为基准(最右侧的数2);变量l记录数组头位置,变量r记录尾位置 2.从l位置开始找到大于基准数的位置。l位置元素与基准数比较,3>2,3和r位置数据交换,r减1 3.从r位置开始找到小于基准数的位置。r位置元素与基准数比较,7>2,r减1;5>2,r减1;1<2,1和l位置数据交换,l加1; 4.重复步骤2,l>=r时停止,此时数原创 2021-11-01 15:23:56 · 143 阅读 · 0 评论 -
有苦有乐的算法 --- 小和问题
题目 一个无序数组,获取每个元素在左面比这个元素小的个数,求这些个数的和 例: [3,2,5,1,4] ==> 6 [4,7,0,8,2,4,9,4] ==> 14 解析 准备一个无序数组, 将这个数组平均分成两部分,再把每一部分在平均分成两部分,以此类推,直到分成只剩一个数为止; 最右侧的[1,4]先合并,[1]为左部分,[4]为右部分,合并时左部分的1比右部分的4小,小和个数+1; 之后[3,2]合并,[3]为左部分,[2]为右部分,合并时左部分的[3]不比右部分的[2]小,小和个数不原创 2021-10-29 17:22:57 · 89 阅读 · 0 评论 -
有苦有乐的算法 --- 归并排序
题目 对无序数组进行归并排序,使其有序 解析 准备一个无序数组, 将这个数组平均分成两部分,再把每一部分在平均分成两部分,以此类推,直到分成只剩一个数为止 在将每一部分排序后依次返回 代码 public static void process(int[] arr, int L, int R) { if (L == R) { return; } int mid = L + ((R - L) >> 1); process(arr, L, mid); process(arr, m原创 2021-10-29 16:06:59 · 131 阅读 · 0 评论 -
有苦有乐的算法 --- 自定义一个栈,实现压栈(push)、弹栈(pop)、获取站内最小值(getmin)
题目 自己定义一个栈的class,要求此栈有三个方法push、pop、getmin push:往栈中压入一个数据 pop:从栈中弹出一个数据 gitmin:过去这个栈中最小的数据单不弹出 解析 准备两个栈stackData、stackMin 压栈时, stackData压入数据; stackMin栈顶数据大于需要压入的数据,stackMin也压入这个数据,stackMin栈顶数据小于需要压入的数据,重复压入stackMin栈顶数据。 例如需要压入的数据依次是:[4,7,3,5,1] 弹栈时,stackD原创 2021-10-29 11:39:43 · 490 阅读 · 0 评论 -
有苦有乐的算法 --- 使用队列结构实现栈结构
题目 队列实现栈 解析 首先准备两个队列queue1、queue2 数据[1,2,3,4,5]依次入队queue1,之后把[1,2,3,4]依次出兑在入队到queue2,[5]留在queue1中 此时[5]在出队可实现"出栈"操作,[5]出队都queue2中的数据依次返回queue1中,新加的元素此时接在其后即可 代码 public static class TwoQueueStack<T> { public Queue<T> queue; public Queue<原创 2021-10-28 15:02:10 · 111 阅读 · 0 评论 -
有苦有乐的算法 --- 使用栈结构实现队列结构
题目 栈实现队列 解析 两个栈,stack1,stack2 假如一组元素为[1,2,3,4,5], 先依次入stack1 在将stack1的所有数据出栈,在入stack2 注:stack1里的的数据一定要一起出栈;stack2中有数据stack1里的的数据不能出栈 stack2出栈即可实现队列操作 代码 public static class TwoStacksQueue { public Stack<Integer> stackPush; public Stack<Intege原创 2021-10-27 17:40:18 · 84 阅读 · 0 评论 -
有苦有乐的算法 --- 一个数组中,有两种数出现了奇数次,其余数都出现了偶数次,找到这两种数
题目 一个数组中,有两种数出现了奇数次,其余数都出现了偶数次,找到这两组数 例: [2,4,3,2,5,4] ⇒ [3,5] [1,4,6,3,7,8,3,2,1,2,6,6,7,8] ⇒ [6,4] 解析 异或:0^N=N;N^N=0;(a^b)^c=a^(b^c) 假设满足条件的数组:[2,4,3,2,5,4] ; 用0去异或数组中每一个数 0^2^4^3^2^5^4 = 0^(2^2)^(4^4)^3^5=3^5,可得: 一个满足条件的数组,这两个出现了奇数次的数记为a和b;0异或这个数组可以可得到a原创 2021-10-27 16:17:49 · 604 阅读 · 0 评论 -
有苦有乐的算法 --- 一个int类型的数,换成二进制后,提取最右侧的1所在位置
问题 一个int类型的数,换成二进制后,提取最右侧的1所在位置 3 = 00000011 ==> 00000001 = 1 4 = 00000100 ==> 00000100 = 4 解析 如图所示: N&(~N+1)就得到了所需要的数 ~N+1=-N所N&-N即为结果 代码 public static int bit1counts(int N) { int rightOne = N & (-N); return rightOne ; } ...原创 2021-10-25 17:01:21 · 308 阅读 · 0 评论 -
整数的原码、反码、补码、移码
计算机再存储一个数时是已二进制的方式存储的,并且第一个作为符号位(0代表正数,1代表负数) 例: byte temp = 3; 3表示为:00000011 对于一个正数来说,原码、反码、补码是相同的,移码为补码的符号位取反 例: 元素:+3 原码:00000011 反码:00000011 补码:00000011 移码:10000011 对于一个负数来说,原码, 反码为原码不带符号位的取反, 补码为其反码加1, 移码为补码的符号位取反 例: 元素:-3 原码:10000011 反码:11111100 补码:1原创 2021-10-25 16:39:47 · 3337 阅读 · 5 评论 -
二进制运算之与(&)、或(|)、非(~)、异或(^)
与(&) 1&1=1否知为0 例: 或(|) 0|0=0否知为1 例: 非(~) 1变0,0变1 例: 注:正数取反之后变成了负数的补码,整体再取反后在加负号才是实际值 异或(^) 0^1=1否知为0 例:原创 2021-10-25 16:10:42 · 577 阅读 · 0 评论 -
有苦有乐的算法 --- 在一个数组中,有一种数出现了奇数次,其余数都出现了偶数次,找到这种数
题目 在一个数组中,有一种数出现了奇数次,其余数都出现了偶数次,找到这种数 例: [1,1,4] ==> 4 [1] ==> 1 [2,3,6,3,1,2,1] ⇒ 6 解析 因为N^N=0; N^0=N。所以 0^N^N^…^N^N(偶数个N)=0; 0^N^N^…^N(奇数个N)=N 由于异或是满足交换律的,所以 0^M^N^…^M^N(偶数个N,偶数个M)=0; 0^M^N^…^M^N^N(奇数个N,偶数个M)=N 假设此数组为: [4,4,4,5,5,3,3,7,7,7,7,1,1,1,原创 2021-10-25 15:46:19 · 510 阅读 · 0 评论 -
有苦有乐的算法 --- 两个元素交换的三种方式
方式一 public static void swap(int[] arr, int i, int j) { arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; } 缺点:自身异或自身等于0,在部分场景使用可能出现问题 方式二 public static void swap(int[] arr, int i, int j) { int temp = arr[i];原创 2021-10-20 11:41:00 · 223 阅读 · 0 评论 -
有苦有乐的算法 --- 有序数组中的元素存在问题、最左元素问题和无序数组局部最小问题
一个有序数组,判断是否含有一个元素 解析: 给定一个数组 如果需要判断是否存在的元素为3。 首先找到数组的中间元素; 如果此元素为3,结束; 如果不是,此元素与3比较,此元素如果大于3,在从此元素左边的部分数组寻找中间元素,以此类推。 如果查找到最后都不是3,证明3在数组中不存在。 代码: public static boolean isExistInArray(int[] sortedArr, int num) { if (sortedArr == null || sortedArr.length原创 2021-10-20 11:21:22 · 165 阅读 · 0 评论